前言:
因为工作需要,最近接触 Golang 比较多。
也希望自己的技术栈能从一个 iOS 转变成 iOS / Golang。
那么,今天我们来聊一聊Golang中的数组(Array
)和切片(Slice
)。
一、Array(数组)
数组我们肯定都是熟悉的,
在Go语言中数组(Array
)在初始化后,长度是固定的。
与其他语言类似,在这里举一些在Go中数组的简单demo。
var arr [10]int // 声明,len与cap为10,值默认补0。
arr := []int {1,2,3,4} // 快速声明,len与cap为4,值为[1,2,3,4]。
arr := [5]int {1,2,3,4} // 快速声明,len与cap为5,值为[1,2,3,4,0],末尾默认补0。
// 数组的遍历
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
二、Slice(切片)
接下来是今天的主角:Slice。
首先,切片是一种引用类型。(与字典map
、通道channel
一样,都是引用类型)
有点类似于我们iOS中的MutableArray
。
暂时可理解为一种可变长的“动态数组”。
注意:
因此,我们取数组的切片时,如果不希望切片的修改会对原有数组产生影响的话,需要对Slice
进行Copy
操作。
基本使用
numbers := []int{1,2,3,4,5,6,7,8,9,10}
// 半闭半开结构
slice1 := numbers[:] // 直接对numbers的引用
slice1 = numbers[1:10] // 从numbers[1]到numbers[9]
slice1 = numbers[:5] // 从开始到numbers[4]
slice1 = numbers[7:] // 从numbers[7]开始到末尾
slice1 = append(slice1, 1,2,3,4,5) // 追加长度
fmt.Println(slice1) // 打印:[8 9 10 1 2 3 4 5]
slice2 := make([]int, len(slice1), cap(slice1)*2) // 手动声明一个slice2,最大长度cap为slice1的两倍。
copy(slice2,slice1) //将slice1的数据copy到slice2
slice2 = append(slice2,1,2,3) // 在对slice2进行追加
fmt.Println(slice1) // 打印:[8 9 10 1 2 3 4 5]
fmt.Println(slice2) // 打印:[8 9 10 1 2 3 4 5 1 2 3]
fmt.Printf("len = %d, cap = %d", len(slice1), cap(slice1)) // 打印当前长度len,与最大容量cap。
扩容策略
当Slice
的长度(len
)即将超过最大容量(cap
)时,Go语言会对Slice
进行扩容。
具体策略为:
- 当
Slice
的长度(len
)小于1024
时,Go语言会对该Slice
进行 “2倍”扩容 。 - 当
Slice
的长度(len
)大于等于1024
时,Go语言会对该Slice
进行 “1.25倍”扩容 。
len | 扩容策略 |
---|---|
<1024 | 2倍扩容 |
>=1024 | 1.25倍扩容 |
感兴趣的同学,可以使用下面的代码,自己试一下它的扩容策略。
slice2 := make([]int,10,10)
fmt.Printf("len = %d, cap = %d\n", len(slice2), cap(slice2)) // 打印当前长度len,与最大容量cap。 // 获取len与cap的长度。
slice2 = append(slice2, 1,2,3,4,5) // 追加数据
fmt.Printf("len = %d, cap = %d\n", len(slice2), cap(slice2)) // 打印当前长度len,与最大容量cap。 // 获取len与cap的长度。
一些注意点(坑)
切记切记,切片是一种引用类型。如果改切片的值不希望改动原有数据,一定要先copy一份。
对切片的遍历时,系统会对value进行一次值拷贝。因此不能对value进行引用操作,否则可能会造成panic。如果需要引用操作,请去下标。
有疑问加站长微信联系(非本文作者)