Go 包括了一些预先定义类型(Pre-declared Type),这包括了布尔、数字与字符串类型。
布尔类型
预定义类型也是具有名称的类型(Named Type),布尔类型名称为bool
,只有两个预先定义的常数true
与false
,由于只有两个值,因此在Go 的规格书中,并没有明确提及bool
的大小,虽然在 Go 官方网站的The Go Playground执行以下代码,会告诉你bool
大小是 1:
package main
import (
"fmt"
"unsafe"
)
func main() {
fmt.Println(unsafe.Sizeof(true))
fmt.Println(unsafe.Sizeof(false))
}
附带一提的是,Go 本身没有提供 REPL 工具,不过 Go 官方网站的The Go Playground是个方便的接口,你也可以在Does Go provide REPL?找到一些其他开发者写的 REPL。
数字类型
数字类型为整数与浮点数的集合,整数部份支持无符号与有符号整数,名称分别为uint
与int
,int
长度会与uint
相同,而uint
长度视平台实现而异,可能是 32 位或是 64 位。
如果想要长度固定,无符号整数的类型名称为uint8
、uint16
、uint32
、uint64
,顾名思义,使用的长度分别为 8 位、16 位、32 位与 64 位,举例来说,uint8
可存储的整数范围为 0 到 255,这也是开发者熟悉的字节类型,而在 Go 中,byte
正是uint8
的别名。
有符号整数的类型名称为int8
、int16
、int32
、int64
,顾名思义,使用的长度分别为 8 位、16 位、32 位与 64 位,举例来说,int32
可存储的整数范围为 -2147483648 到 2147483647,而rune
为int32
的别名,可用来存储 Unicode 码(code point)。
如果直接写下一个整数字面量(literal),例如10
,在没有程序上下文(context)的情况下,10
是未定类型(Untyped),未定义类型整数的默认类型(Default type)为int
类型,在必须得到一个类型而程序上下文未提供时(例如变量定义与赋值要进行类型推断时),就会使用默认类型。
写下10
这样的整数,默认是 10 进制;可以在数字前加上 0,Go 1.13 后可使用 0o 来表示八进制,加上 0x 表示 16 进制,此时 a-f and A-F 都可以用来表示 10 到 15,例如0xBadFace
,G○ 1.13 后可以使用0x1.0p-1021
来表示浮点数。
Go 1.13 后,可以使用0b
来定义二进制数字,例如0b00101101
;数字分隔下划线在 Go 1.13 后可以使用,例如1_000_000
、0b_1010_0110
或3.1415_9265
。
math
模块上定义了一些常数,可以让你得知各整数类型的存储范围,例如以下程序显示了各整数类型的存储范围:
package main
import (
"fmt"
"math"
"reflect"
)
func main() {
fmt.Printf("uint8 : 0 ~ %d\n", math.MaxUint8)
fmt.Printf("uint16 : 0 ~ %d\n", math.MaxUint16)
fmt.Printf("uint32 : 0 ~ %d\n", math.MaxUint32)
fmt.Printf("uint64 : 0 ~ %d\n", uint64(math.MaxUint64))
fmt.Printf("int8 : %d ~ %d\n", math.MinInt8, math.MaxInt8)
fmt.Printf("int16 : %d ~ %d\n", math.MinInt16, math.MaxInt16)
fmt.Printf("int32 : %d ~ %d\n", math.MinInt32, math.MaxInt32)
fmt.Printf("int64 : %d ~ %d\n", math.MinInt64, math.MaxInt64)
fmt.Printf("整数默认类型: %s\n", reflect.TypeOf(1))
}
执行结果如下:
uint8 : 0 ~ 255
uint16 : 0 ~ 65535
uint32 : 0 ~ 4294967295
uint64 : 0 ~ 18446744073709551615
int8 : -128 ~ 127
int16 : -32768 ~ 32767
int32 : -2147483648 ~ 2147483647
int64 : -9223372036854775808 ~ 9223372036854775807
整数默认类型: int
注意到,程序中使用了uint64
函数,对math
的一些常数做了明确的类型转换(Type conversion),这是因为在 Go 中,常数可以是未定类型(Untyped),实际类型会视当时程序环境而定,如果没有可参考的环境信息,会使用默认类型。
在这边的例子中,若是拿掉uint64
,math.MaxUint64
就会采用int
类型而发生 overflow 的错误,使用uint64
函数进行类型转换,让常数有明确的环境信息可以参考,就不会产生这个错误。
在 Go 中,不同类型之间也无法直接进行运算,就算都是整数也不行,例如以下会发生 mismatched types 错误:
package main
import "fmt"
func main() {
var x int32 = 10
var y int16 = 20
fmt.Println(x + y) // mismatched types error
}
想要避免错误,你必须明确进行类型转换,例如写为x + int32(y)
(或者是int16(x) + y
)。那么,下面这个会不会发生错误呢?
package main
import "fmt"
func main() {
var x int8 = 10
fmt.Println(x + 20)
}
不会!结果会显示 30,为什么?正如先前谈过,写下20
这个整数,它是未定类型,根据x + 20
,进行int8
的运算,所以不会发生错误,不这样的话,每次都得写x + int8(20)
,实在就够烦的了!
在 Go 中并没有字符对应的类型,只有码的概念,int32
或其别名rune
可用来存储 Unicode 码,你可以将单一文本包在单引号之中,例如'林'
,这会以int32
存储为 26519,例如fmt.Println('林')
会显示 26519,若想显示为文本,则要使用fmt.Println(string('林'))
。
浮点数的名称为float32
、float64
,分别为 IEEE-754 32 位与 64 位浮点数,如果直接写下一个浮点数字面量,默认类型是float64
类型,可使用科学计数,例如1.e+0
、6.67428e-11
等,常数math.MaxFloat32
、math.MaxFloat64
分别代表着浮点数的最大存储范围。
Go 还有复数(Complex number),其中complex64
、complex128
,可由一个实部数字,加上一个虚部数字与i
来表示复数,例如1 + 2i
,写下一个复数字面量,默认类型为complex128
,虚数的部份,在 Go 1.13 后,之前谈到的数字表示法都可以使用,有三个函数可以用来处理复数,即complex
、real
与imag
,可参考〈Manipulating complex numbers〉。
Go 还有个uintptr
,可以用来存储指针值,这之后有机会再来谈。
字符串类型
Go 的字符串在实现上使用UTF-8,就目前必须先知道的是,当使用双引号包裹一系列文本,会产生字符串类型,默认类型为string
,例如,"Justin"
会创建一个字符串。
如果对字符串使用len
函数,返回的会是字节数量,而不是 Unicode 码的数量;如果使用[]
搭配索引,获取特定索引位置的值,那么返回的会是byte
(uint8
)类型。
在 Go 中,可以对字符串使用切片(slice)操作,返回的类型会是string
类型,例如,"Justin"[0:2]
会返回字符串"Ju"
,不过,这是获取索引 0、1 处的字节,再创建string
返回,因此,对于"语言"
这个字符串,如果想用切片操作获取"语"
这个子字符串,必须使用"语言"[0:3]
,因为 Go 的字符串在实现上使用 UTF-8,一个中文本基本上占三个字节。
Go 的字符串还有许多值得说明的细节,这之后会再做详细讨论。