www.zhblog.net

认识预定义类型


Go 包括了一些预先定义类型(Pre-declared Type),这包括了布尔、数字与字符串类型。

布尔类型

预定义类型也是具有名称的类型(Named Type),布尔类型名称为bool,只有两个预先定义的常数truefalse,由于只有两个值,因此在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。

数字类型

数字类型为整数与浮点数的集合,整数部份支持无符号与有符号整数,名称分别为uintintint长度会与uint相同,而uint长度视平台实现而异,可能是 32 位或是 64 位。

如果想要长度固定,无符号整数的类型名称为uint8uint16uint32uint64,顾名思义,使用的长度分别为 8 位、16 位、32 位与 64 位,举例来说,uint8可存储的整数范围为 0 到 255,这也是开发者熟悉的字节类型,而在 Go 中,byte正是uint8的别名。

有符号整数的类型名称为int8int16int32int64,顾名思义,使用的长度分别为 8 位、16 位、32 位与 64 位,举例来说,int32可存储的整数范围为 -2147483648 到 2147483647,而runeint32的别名,可用来存储 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_0000b_1010_01103.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),实际类型会视当时程序环境而定,如果没有可参考的环境信息,会使用默认类型。

在这边的例子中,若是拿掉uint64math.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('林'))

浮点数的名称为float32float64,分别为 IEEE-754 32 位与 64 位浮点数,如果直接写下一个浮点数字面量,默认类型是float64类型,可使用科学计数,例如1.e+06.67428e-11等,常数math.MaxFloat32math.MaxFloat64分别代表着浮点数的最大存储范围。

Go 还有复数(Complex number),其中complex64complex128,可由一个实部数字,加上一个虚部数字与i来表示复数,例如1 + 2i,写下一个复数字面量,默认类型为complex128,虚数的部份,在 Go 1.13 后,之前谈到的数字表示法都可以使用,有三个函数可以用来处理复数,即complexrealimag,可参考〈Manipulating complex numbers〉。

Go 还有个uintptr,可以用来存储指针值,这之后有机会再来谈。

字符串类型

Go 的字符串在实现上使用UTF-8,就目前必须先知道的是,当使用双引号包裹一系列文本,会产生字符串类型,默认类型为string,例如,"Justin"会创建一个字符串。

如果对字符串使用len函数,返回的会是字节数量,而不是 Unicode 码的数量;如果使用[]搭配索引,获取特定索引位置的值,那么返回的会是byteuint8)类型。

在 Go 中,可以对字符串使用切片(slice)操作,返回的类型会是string类型,例如,"Justin"[0:2]会返回字符串"Ju",不过,这是获取索引 0、1 处的字节,再创建string返回,因此,对于"语言"这个字符串,如果想用切片操作获取"语"这个子字符串,必须使用"语言"[0:3],因为 Go 的字符串在实现上使用 UTF-8,一个中文本基本上占三个字节。

Go 的字符串还有许多值得说明的细节,这之后会再做详细讨论。


展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情