Go 语言基础 - 数组与切片
数组 array
是许多语言中都会有的基本数据结构,它是我们开辟的存储相同数据类型的一连串地址空间(长度不可变),通过下标寻址,随机访问性能为O(1)。
切片 slice
可以当做是长度可变
的数组,在使用上与数组相同(初始化的方式有区别)。
数组(array)
我们可以通过下面的方式初始化数组,下面的例子都是初始化长度为5的数组:
1 | // 声明式 |
注意,数组在声明或赋值初始化后,对于没有主动初始化的空间,它会使用被声明的类型的初始值进行填充。
比如上面的arr4,它的具体内容将是:[1 2 3 0 0]
在数组的使用上,我们通过下标进行访问,下标从0
开始:
1 | var arr7 [5]int |
切片(slice)
切片在初始化上与数组不太相同,我们不需要指定长度,另外可以使用内建函数make
来开辟空间:
下面会提到 *容量* 这个上面没有提到的词,可先暂且知道它的存在,更后面会详细说到
1 | // 声明式,这是长度为0的切片 |
跟数组相似,当我们为切片开辟了空间之后,没有主动初始化的空间,将会使用被声明的类型的初始值填充。
同样的,切片通过下标来访问切片元素,
1 | slice7 := make([]int, 5) |
切片的扩容
内置函数append
可以对切片进行元素的添加。这也是切片跟数组最大的区别之处。
1 | slice8 := []int{1, 2, 3, 4, 5} |
截取片段
数组和切片支持获取片段的功能:
1 | arr8 := [5]int{1, 2, 3, 4, 5} |
需要注意的是,截取是左闭右开区间。
长度与容量
数组和切片,它们都有长度
和容量
的概念,只不过对于数组来说,容量便等于长度。
对于切片来说,容量
是针对其底层数组而言的,当我们使用append
对切片进行增加的时候,假如增加后的切片长度超过了容量,那么切片需要对底层数组进行扩容
,这个扩容,实际上是重新开辟一片数组空间,同时给到新
的切片。如果增加后的长度没有超过容量,那么返回的切片还是原来的底层数组,不会有所改变,只是看到的内容变多了。
所以在使用
append
时,其实是隐藏了一些陷阱
在里面,文章的最后面会对这部分继续描述。
通过内置函数len
,我们可以得到数组和切片的实际长度,而通过内置函数cap
,我们可以得到数组和切片的容量:
1 | slice10 := make([]int, 5, 10) |
遍历
通过关键字range
,我们可以很方便地对数组或切片进行遍历:
1 | arr9 := [...]int{1, 2, 3, 4, 5} |
越界错误
数组和切片的访问,下标是从0开始,假设访问的下标>=长度时,就会发生越界错误。
当对数组的访问越界,而且编译器能直接推断出越界时,编译会不通过,而避免运行时才报错。
1 | arr10 := [5]int{1, 2, 3, 4, 5} |
复杂类型
数组和切片的类型,可以是复杂的类型,比如数组、结构体、切片。
当类型是数组时,此时就变成了一个二维数组,或者是更高维的数组:
1 | // 初始化了一个二维数组 |
类型为结构体时:
1 | type Student struct { |
切片的底层数组
我们知道,在使用内建函数append
对切片进行增加时,如果容量不够,则会开辟一片新的内部数组空间,交给新的切片,这个时候我们只需要接收到新的切片进行后续操作即可。而当容量足够时,append
会直接使用原有空间进行操作。
所以,我们了解到这个细节后,需要留意出现的状况:
- 容量足够时,切片会使用原有内置数组
1 | slice12 := make([]int, 5, 10) |
我建议你手动运行下结果,然后根据容量与长度的问题稍微思考下,可能会更深刻一些。
- 根据容量,主动为切片设置长度
因为我们知道了切片的底层是个数组后,我们可以手动对切片的长度进行操作,比如:
1 | slice16 := make([]int, 5, 10) |
总结
文章从初始化、使用方式、细节等方面介绍了数组和切片,如有错漏或补充,十分欢迎各位进行补充改正。
- 本文链接:https://keepmoving.ren/golang/array-and-slice/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!