Go语言-容器类型
第 6 章 容器类型
6.1 数组
数组 是一个由 固定长度 的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,因此在 Go 语言中很少直接使用数组。和数组对应的类型是 slice(切片) ,它是可以动态的增长和收缩的序列, slice
功能也更灵活,下面我们再讨论 slice
。
6.1.1 数组声明
可以使用 [n]Type
来声明一个数组。其中 n
表示数组中元素的数量, Type
表示每个元素的类型。
1 | package main |
6.1.2 数组长度
使用内置的 len
函数将返回数组中元素的个数,即数组的长度。
1 | func arrLength() { |
6.1.3 数组遍历
使用 for range
循环可以获取数组每个索引以及索引上对应的元素。
1 | func showArr() { |
6.1.4 数组是值类型
Go 中的数组是值类型而不是引用类型。当数组赋值给一个新的变量时,该变量会得到一个原始数组的一个副本。如果对新变量进行更改,不会影响原始数组。
1 | func arrByValue() { |
6.2 切片(Slice)
切片是对数组的一个连续片段的引用,所以切片是一个引用类型。切片 本身不拥有任何数据,它们只是对现有数组的引用,每个切片值都会将数组作为其底层的数据结构。slice 的语法和数组很像,只是没有固定长度而已。
6.2.1 创建切片
使用 []Type
可以创建一个带有 Type
类型元素的切片。
1 | // 声明整型切片 |
你也可以使用 make
函数构造一个切片,格式为 make([]Type, size, cap)
。
1 | numList := make([]int, 3, 5) |
当然,我们可以通过对数组进行片段截取创建一个切片。
1 | arr := [5]string{"Go语言极简一本通", "Go语言微服务架构核心22讲", "从0到Go语言微服务架构师", "微服务", "分布式"} |
6.2.2 切片的长度和容量
一个 slice 由三个部分构成:指针 、 长度 和 容量 。指针指向第一个 slice 元素对应的底层数组元素的地址,要注意的是 slice 的第一个元素并不一定就是数组的第一个元素。长度对应 slice 中元素的数目;长度不能超过容量,容量一般是从 slice 的开始位置到底层数据的结尾位置。简单的讲,容量就是从创建切片索引开始的底层数组中的元素个数,而长度是切片中的元素个数。
内置的 len
和 cap
函数分别返回 slice 的长度和容量。
1 | s := make([]string, 3, 5) |
如果切片操作超出上限将导致一个 panic
异常。
1 | s := make([]int, 3, 5) |
Tips:
由于 slice 是引用类型,所以你不对它进行赋值的话,它的默认值是
nil
1
2var numList []int
fmt.Println(numList == nil) // true切片之间不能比较,因此我们不能使用
==
操作符来判断两个 slice 是否含有全部相等元素。特别注意,如果你需要测试一个 slice 是否是空的,使用len(s) == 0
来判断,而不应该用s == nil
来判断。
6.2.3 切片元素的修改
切片自己不拥有任何数据。它只是底层数组的一种表示。对切片所做的任何修改都会反映在底层数组中。
1 | func modifySlice() { |
这里的 arr[:]
没有填入起始值和结束值,默认就是 0
和 len(arr)
。
6.2.4 追加切片元素
使用 append
可以将新元素追加到切片上。append
函数的定义是 func append(slice []Type, elems ...Type) []Type
。其中 elems ...Type
在函数定义中表示该函数接受参数 elems
的个数是可变的。这些类型的函数被称为可变函数。
1 | func appendSliceData() { |
当新的元素被添加到切片时,如果容量不足,会创建一个新的数组。现有数组的元素被复制到这个新数组中,并返回新的引用。现在新切片的容量是旧切片的两倍。
6.2.5 多维切片
类似于数组,切片也可以有多个维度。
1 | func mSlice() { |
6.3 Map
在 Go 语言中,map 是散列表(哈希表)的引用。它是一个拥有键值对元素的无序集合,在这个集合中,键是唯一的,可以通过键来获取、更新或移除操作。无论这个散列表有多大,这些操作基本上是通过常量时间完成的。所有可比较的类型,如 整型
,字符串
等,都可以作为 key
。
6.3.1 创建 Map
使用 make
函数传入键和值的类型,可以创建 map 。具体语法为 make(map[KeyType]ValueType)
。
1 | // 创建一个键类型为 string 值类型为 int 名为 scores 的 map |
我们也可以用 map 字面值的语法创建 map ,同时还可以指定一些最初的 key/value :
1 | var steps2 map[string]string = map[string]string{ |
或者
1 | steps3 := map[string]string{ |
6.3.2 Map 操作
添加元素
1
2// 可以使用 `map[key] = value` 向 map 添加元素。
steps3["第四步"] = "总监"更新元素
1
2// 若 key 已存在,使用 map[key] = value 可以直接更新对应 key 的 value 值。
steps3["第四步"] = "CTO"获取元素
1
2// 直接使用 map[key] 即可获取对应 key 的 value 值,如果 key不存在,会返回其 value 类型的零值。
fmt.Println(steps3["第四步"] )删除元素
1
2//使用 delete(map, key)可以删除 map 中的对应 key 键值对,如果 key 不存在,delete 函数会静默处理,不会报错。
delete(steps3, "第四步")判断 key 是否存在
1
2
3
4
5
6
7
8// 如果我们想知道 map 中的某个 key 是否存在,可以使用下面的语法:value, ok := map[key]
v3, ok := steps3["第三步"]
fmt.Println(ok)
fmt.Println(v3)
v4, ok := steps3["第四步"]
fmt.Println(ok)
fmt.Println(v4)这个语句说明
map
的下标读取可以返回两个值,第一个值为当前key
的value
值,第二个值表示对应的key
是否存在,若存在ok
为true
,若不存在,则ok
为false
。遍历 map
1
2
3
4// 遍历 map 中所有的元素需要用 for range 循环。
for key, value := range steps3 {
fmt.Printf("key: %s, value: %s\n", key, value)
}获取 map 长度
1
2
3
4
5// 使用 len 函数可以获取 map 长度
func createMap() {
//...
fmt.Println(len(steps3)) // 4
}
6.3.3 map 是引用类型
当 map
被赋值为一个新变量的时候,它们指向同一个内部数据结构。因此,改变其中一个变量,就会影响到另一变量。
1 | func mapByReference() { |
当 map
作为函数参数传递时也会发生同样的情况。
如何学习Go语言微服务,快速步入架构师


添加微信 | 公众号更多内容 |
---|---|
![]() |
![]() |