-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
注:slice 中文翻译做切片,个人以为并不贴切,所以本文不使用切片称呼。
前言
编程语言的学习都绕不开数据类型这个话题,而数组作为支持最广泛的基础数据类型,其定义和使用在各个语言中基本大同小异。从这一点上说,编程语言互相借鉴(抄袭)一点都没有错。但之所以还会有这么多编程语言被发明和使用,是因为他们的应用场景或有所不同。比如偏重于组织复杂业务逻辑的,或者高并发性能的。
golang 中的数组的定义和使用都及其简单,但依然有他特别的地方,值得记录下来,以供查阅和分享。
数组初始化
定义数组只需要给出下面两个要素
- 元素类型
- 长度或者初始化元素
比如,创建一个长度为 2 的字符串数组,并赋值:
arr1 := [2]string{}
arr1[0] = "a"
arr1[1] = "b"或者,初始化同时赋值
arr1 := []string{"a", "b"}此时,长度值可以省略,数组长度以初始元素个数为准。
操作数组
通过下标的方式访问数组元素,这个没什么可说的,java 如此,js 亦如此。
arr1[0]
更新:
arr1[0] = "a1"
数组的长度固定,所以,访问超出限制的下标将会导致 panic 程序中断。
index out of bounds
slice
slice 是对数组的一种高级抽象,底层存储依赖数组。实际项目中,slice 可以用作“可变长”数组。有两种定义 slice 的方法。
通过指定初始下标和结束下标(不包含)选取部分元素,如:
slice1 := arr1[0:1]使用 make 函数,三个参数分别为初始化数组,长度,容量:
slice2 := make([]string{}, 2, 4)可以看到,两种定义办法,都少不了一个底层数组。
操作 slice
访问和更新元素的方式和普通数组相同,所不同的是,slice 可以增加长度,这是个很有实际意义的特质。因为很多业务场景下,并不能确定元素的个数。
前面说到 slice 底层存储依然是数组,但数组是定长的,slice 是如何做到可变长的呢?通过下面的小实验可以稍微猜度一下。
func print(s []string) {
fmt.Printf("len(%d),cap(%d),elements:%s , %p \n", len(s), cap(s), s, s)
}
func main() {
s := make([]string, 1, 2)
print(s)
s[0] = "a"
print(s)
s = append(s, "b")
print(s)
s = append(s, "c")
print(s)
}结果:
len(1),cap(2),elements:[] , 0x40c0e0
len(1),cap(2),elements:[a] , 0x40c0e0
len(2),cap(2),elements:[a b] , 0x40c0e0
len(3),cap(4),elements:[a b c] , 0x442260
当 cap 达到限制后,append 会返回一个新的 slice(注意新指针地址 0x442260),以及更大的 cap。所以,可以猜想,当 cap 发生变化时,Go 会创建一个新的数组,并将指针指向此数组。