4.1 数组的内部实现和基础功能
4.1.1 内部实现
长度固定、内存连续分配、CPU数据缓存更久、容易计算索引,迭代速度快
4.2.1 声明和初始化
声明需要类型和长度,长度一旦确定就不能改变1
var array [5] int
声明变量时,会使用对应类型的零值对变量进行初始化
可以使用字面变量声明数组1
array := [5]int{10, 20, 30, 40, 50}
也可以使用…替代数组长度,Go会根据初始化时数组元素的数量来确定数组的长度1
array := [...]int{10, 20, 30, 40, 50}
还可以给指定位置赋值确定值1
array := [5]int{1: 10, 2: 20}
4.1.3 使用数组
1 | array := [5]int{10, 20, 30, 40, 50} |
4.1.4 多维数组
1 | // 声明一个二维整型数组,两个维度分别存储4 个元素和2 个元素 |
4.1.5 在函数间传递数组
内存和性能上,传递数组是个很大的开销,因为总是值传递,需要拷贝,可以使用指针在函数间传递大数组,但是传递指针,函数会有改变指针指向的值的权限1
2
3
4
5
6
7var array [1e6]int
// 将数组的地址传递给函数foo
foo(&array)
// 函数foo 接受一个指向100 万个整型值的数组的指针
func foo(array *[1e6]int) {
...
}
4.2 切片的内部实现和基础功能
切片类似于动态数组,可以按需自动增长和缩小,通过内置append函数,可以高效增长切片,切片在内存中连续分配,可以索引、迭代
4.2.1 内部实现
三个要素:指向底层数组的指针、切片访问元素的个数(即长度)和切片允许增长到的元素个数(即容量)
4.2.2 创建和初始化
1 | // 创建一个字符串切片 |
4.2.3 使用切片
1 | // 创建一个整型切片 |
4.2.4 多维切片
1 | // 创建一个整型切片的切片 |
4.2.5 在函数间传递切片
1 | // 成本很低,在 64 位架构的机器上,一个切片需要24 字节的内存:指针字段需要8 字节,长度和容量 |
4.3 映射的内部实现和基础功能
4.3.1 内部实现
桶 + 两个数组
key转换成散列值,散列低位表示桶的序号,每个桶内有两个数组构成,第一个数组存储散列键的高发位置,第二个数组是一个字节数组,用于存储键值对,该字节数组先依次存储了这个桶里的所有键,
之后依次存储了这个桶里的所有值。
4.3.2 创建和初始化
映射的键可以是任何可以使用(==)比较的值,切片、函数以及包含切片的结构类型不能作为映射的键,因为他们包含引用语义1
2
3
4
5
6
7
8
9
10// 创建一个映射,键的类型是string,值的类型是int
dict := make(map[string]int)
// 创建一个映射,键和值的类型都是string
// 使用两个键值对初始化映射
dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
// 创建一个映射,使用字符串切片作为映射的键
dict := map[[]string]int{}
// Compiler Exception:
// invalid map key type []string
4.3.3 使用映射
1 | // 创建一个空映射,用来存储颜色以及颜色对应的十六进制代码 |
4.3.4 在函数间传递映射
在函数间传递映射并不会制造出该映射的副本,实际上,当传递映射给一个函数,并对这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改,和切片类似1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32func main() {
// 创建一个映射,存储颜色以及颜色对应的十六进制代码
colors := map[string]string{
"AliceBlue": "#f0f8ff",
"Coral": "#ff7F50",
"DarkGray": "#a9a9a9",
"ForestGreen": "#228b22",
}
// 显示映射里的所有颜色
for key, value := range colors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
// 调用函数来移除指定的键
removeColor(colors, "Coral")
// 显示映射里的所有颜色
for key, value := range colors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
}
// removeColor 将指定映射里的键删除
func removeColor(colors map[string]string, key string) {
delete(colors, key)
}
// output
// Key: AliceBlue Value: #F0F8FF
// Key: Coral Value: #FF7F50
// Key: DarkGray Value: #A9A9A9
// Key: ForestGreen Value: #228B22
// Key: AliceBlue Value: #F0F8FF
// Key: DarkGray Value: #A9A9A9
// Key: ForestGreen Value: #228B22
4.4 小结
数组是构造切片和映射的基石
Go语言里切片经常用来处理数据的集合,映射用来处理具有键值对结构的数据
内置函数make可以创建切片和映射,并指定原始的长度和容量,也可以直接使用切片和映射字面量,或者使用字面量作为变量的初始值
切片有容量限制,不过可以使用内置的append函数扩展容量
映射的增长没有容量或者任何限制
内置函数len可以用来获取切片或者映射的长度
内置函数cap只能用于切片
通过组合,可以创建多维数组和多维切片。也可以使用切片或者其他映射作为映射的值,但是切片不能用作映射的键
将切片或者映射传递给函数的成本很小,并且不会复制底层的数据结构