Go基本类型概述
概念:基本类型(basic type)
- 内置字符串类型:
string
- 内置布尔类型:
bool
- 内置数值类型:
int8
、uint8(byte)
、int16
、uint16
、int32(rune)
、uint32
、int64
、int
、uint
、uintptr
float32
、float64
complex64
、complex128
注意,byte
是uint8
的一个内置别名,rune
是int32
的一个内置别名。
概念:组合类型(composite type)
Go支持下列组合类型:
- 指针类型 - 类C指针
- 结构体类型 - 类C结构体
- 函数类型 - 函数类型在Go
- 容器类型,包括:
- 数组类型 - 定长容器类型
- 切片类型 - 动态长度和容量容器类型
- 映射类型(map) - 也常称为字典类型。在标准编译器中映射是使用哈希表实现的
- 通道类型 - 通道用来同步并发的协程
- 接口类型 - 接口在反射和多态中发挥着重要角色
组合类型可以用它们各自的字面表示形式来表示。下面是一些各种不同类型的组合类型字面表示形式的例子:
// 假设T为任意一个类型,Tkey为一个支持比较的类型
*T // 一个指针类型
[5]T // 一个元素类型为T、元素个数为5的数组类型
[]5 // 一个元素类型为T的切片类型
map[Tkey]T // 一个键值类型为Tkey、元素类型为T的映射类型
// 一个结构体类型
struct {
name string
age int
}
// 一个函数类型
func(int) (bool,string)
// 一个接口类型
interface {
Method0(string) int
Method1() (int,bool)
}
// 几个通道类型
chan T
chan <- T
<-chan T
语法:类型定义(type definition declaration)
类型定义又称类型定义声明。在Go1.9之前,类型定义被称为类型声明并且是唯一的一种类型声明形式。但是自从Go1.9,类型定义变成了两种类型声明形式之一。另一种新的类型声明形式为 类型别名声明
在Go中,我们可以用如下形式来定义新的类型。在此语法中,type
为一个关键字。
// 定义单个类型
type NewTypeName SourceType
// 定义多个类型
type (
NewTypeName1 SourceType1
NewTypeName2 SourceType2
)
新的类型名必须为标识符。
上例中的第二个类型声明中包含两个类型描述(type specification)。如果一个类型声明包含多于一个的类型描述,这些类型描述必须用一对()
括起来。
注意:
- 一个新定义的类型和它的源类型为两个不同的类型
- 在两个不同的类型定义中的定义的两个类型肯定为两个不同的类型
- 一个新定义的类型和它的源类型的底层类型一致并且它们的值可以相互显示转换
- 类型定义可以出现在函数体内
语法:类型别名声明(type alias declaration)
上面已经提到了,Go中有两个内置类型别名:byte
(类型uint8
的别名)和rune
(类型int32
的别名)。在Go1.9之前,它们是Go中仅有的两个类型别名。
从Go1.9开始,我们可以使用下面的语法来声明自定义类型别名。此语法和类型定义类似,但是请注意其中多了一个等号=
。
type (
Name = string
Age = int
)
type table = map[string]int
type Table = map[Name]Age
类型别名也必须为标识符。同样的,类型别名可以被声明在函数体内。注意,别名类型和源类型是同一类型。
概念:定义类型和非定义类型(defined type and undefined type)
一个定义类型是一个在某个类型定义声明中定义的类型。所有的基本类型都是定义类型。一个非定义类型一定是一个组合类型。
在下面的例子中,别名C
和类型字面量[]string
都表示同一个非定义类型。类型A
和别名B
均表示同一个定义类型。
type A []string
type B = A
type C = []string
概念:有名类型和无名类型(named type and unnamed type)
在Go1.9之前,有名类型这一术语准确的定义在Go白皮书中。它曾被定义为一个有名字的类型。随着Go1.9中引入的类型别名新特性,此术语被从白皮书中删除了,原因是它可能会造成一些理解上的困惑。比如,一些类型字面表示(比如上面出现的别名C
)是一个标识符(即一个名称),但是它们所表示的类型(比如[]string
)在Go1.9之前却被称为无名类型。
为了避免出现这样的困惑,从Go1.9开始,一个新的术语定义类型被引入来填补移除有名类型后的空白。但是也会有一些解释上的障碍。为了避免这样的障碍,Go语言101中的文章将遵守如下原则:
- 术语有名类型和定义类型将被视为完全相同的概念
- 一个类型别名将不会被称为一个类型,尽管我们常说它表示着一个类型
- 当我们提及一个类型名(称),它可能是一个定义类型的名称,也可能是一个类型别名的名称。
概念:底层类型(underlying type)
在Go中,每个类型都有一个底层类型。规则:
- 一个内置类型(包括
unsafe
标准库包中定义的Pointer
类型)的底层类型为它自己 - 一个非定义类型(必为一个组合类型)的底层类型为它自己
- 在一个类型声明中,新声明的类型和源类型共享底层类型
一个例子:
// 这四个类型的底层类型均为内置类型int
type (
MyInt int
Age MyInt
)
// 下面这三个新声明的类型的底层类型各不相同
type (
IntSlice []int // 底层类型为[]int
MyIntSlice []MyInt // 底层类型为[]MyInt
AgeSlice []Age // 底层类型为[]Age
)
// 类型[]Age、Ages和AgeSlice的底层类型均为[]Age
type Ages AgeSlice
如何溯源一个声明的类型的底层类型?规则很简单,在溯源过程中,当遇到一个内置类型或者非定义类型时,溯源结束。以上面这几个声明的类型为例,下面是它们的底层类型的溯源过程:
MyInt -> int
Age -> MyInt -> int
IntSlice -> []int
MyIntSlice -> []MyInt
AgeSlice -> Age[]
Ages -> AgeSlice -> []Age