本文首发于 PRSDigg(顶呱呱) © 2022 阿坦
转载请注明出处
原创不易,请多转发点赞
Golang 的世界里,有最恶名昭彰,实力最强的 4 种数据类型。彼此之间处于竞争关系,但是各有各的特色。由此,各自有各自的生存空间。
它们分别是数组、切片、映射、构建存储(struct)。
数组
// 数组变量声明
var array [5]int
可以看到,数组是一个集合,里面的值都是同一类型,同时,数组在声明的时候就已经限定了元素数量,本例为 5 个元素。有额外的元素想要添加到这个数组怎么办?没办法。这时,如果能有一种可以拓展元素数量的数组,有拓展需求的码农我想一定会很开心。于是,切片出现了……
切片
// 切片的声明
var mySlice []string
通过切片的声明语句,可以看到,切片变量不需要在声明时确定元素数量。也就是说,想给它添加几个元素就可以给它添加几个元素,切片在元素数量上可以更自由。
怎么实现的呢?
切片实际上是一个数组的一个片段。1
在声明切片时,内存里实际上先创建了一个数组,拿来给这个切片使用。
不是说数组是一种在声明时就确定了元素数量的东西吗?那当它里面的切片拓展超过了容纳它的数组规定的数量时,不就没法实现了吗?
答案是 No
数组和切片的关系可以这么理解:数组是切片的宿主。
切片想要自由扩张,当它的宿主(数组)容量不够时,它就换一个容量更大的数组。切片接着扩张,宿主容量又不够了,换更大的数组。如此往复……
映射(map)
// 映射的声明
var nilMap map[string]bool
nilMap = make(map[string]bool)
nilMap["guitar"] = true
nilMap["dance"] = false
数组、切片都是由索引和值构成。在数组创建时,索引就自动添加好了,从 0 开始递增,每个索引对应一个元素。
映射跟数组说:“这个索引你不要自动添加,我要手动添加。另外,索引类型也不一定非得是整数,由我自己来决定。” 然后,映射把自己定义的索引叫做 key
.
以前面示例中的映射声明打印出来就是这个样子:
map[dance:false guitar:true]
码农前辈遇到了一个疑问, nilMap["swim"]
我们在示例中没有给它赋值,fmt.Println(nilMap["swim"])
输出它的值,会是什么,经过试验答案是 false
.
我没有给 nilMap["swim"]
赋值啊,为什么它会是 false
?
是因为未经赋值的 key
默认是零值,而布尔值的零值是 false
有没有留意到 nilMap["dance"]
的值也等于 false
?
nilMap["dance"] = false
,nilMap["swim"] = false
,区别在于 nilMap["dance"]
这个 false
是我赋给它的,而 nilMap["swim"]
的 false
是默认的。
问题来了,我怎么知道一个 key
当前赋值了没有?
当我们访问一个映射的特定 key
时,会返回两个值:
-
第一个是当前
key
对应的值; -
第二个是一个布尔值,表示它在声明后有没有被赋值:
-
true
就是已经赋值了; -
false
就是还没有赋值。
-
_, ok1 := nilMap["dance"]
_, ok2 := nilMap["swim"]
fmt.Println(ok1, ok2) // 结果: true false
nilMap["dance"]
被赋值了,nilMap["swim"]
还没有,原来是这个意思。
你捋清楚了吗?哪里不清楚欢迎留言告诉我!
构建存储(struct)
一个数组只能存储一种类型的值(切片也一样);
一个映射里所有的 key
是同一种类型,所有的 value
是同一种类型。
我想把不同类型的值存到一个容器里,有办法吗?
构建存储(struct) 应运而生:
package main
import "fmt"
type subscriber struct {
name string
rate float64
active bool
}
func main() {
var subscriber1 subscriber
subscriber1.name = "Aman Singh"
subscriber1.rate = 5.99
subscriber1.active = true
fmt.Println(subscriber1)
}
// 结果:{Aman Singh 5.99 true}
代码解析:
用关键字 type
开头,定义好 struct
要设定一些什么 key
, 每个 key
分别保存什么类型的值,把这种构建类型称为 subscriber
。
之后,在声明变量时,就可以用 subscriber
来确定变量的类型,subscriber
和 int
, string
, bool
, float64
一样使用。
通过代码可以看到,订阅者 1 号 subscriber1
经过构建类型 subscriber
的塑造,成功地同时保存了字符串、浮点数、布尔值。
小结
和打架一个道理,直拳打不着试试摆拳,摆拳不行试试勾拳。
数组不适合考虑下切片,切片不适合考虑下映射(map),映射不适合考虑下构建(struct)。
四大数据类型让你的代码更“能打”。
-
Jay, McGavren. Head First Go. China Machine Press, 2020. ↩