切片slice
其本身并不是数组,它指向底层的数组
作为变长数组的替代方案,可以关联底层数组的局部或全部
为引用类型
- 可以直接创建或从底层数组获取生成
func main() {
// var s1 []int
// fmt.Println(s1) []
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(a) //[1 2 3 4 5 6 7 8 9 0]
s1 := a[5:10] //取数组a中索引5到10的值,包含5,但是不包含10
s2 := a[5:len(a)] //len(a)为数组的长度
s3 := a[5:]
s4 := a[:5] //取前五个值
fmt.Println(s1) //[6 7 8 9 0]
fmt.Println(s2) //[6 7 8 9 0]
fmt.Println(s3) //[6 7 8 9 0]
fmt.Println(s4) //[1 2 3 4 5]
}
- 一般使用make()创建
func main() {
s1 := make([]int, 10,10)
//参数为:类型,包涵多少元素,初始容量,
//如果包含的元素超过容量,比如有11个元素,
//那么就会重新分配一个容量为20( 初始容量翻倍)的内存快
}
- 使用len()获取元素个数,cap()获取容量
func main() {
s1 := make([]int, 3, 10)
fmt.Println(s1) //[0 0 0]
fmt.Println(len(s1)) //3
fmt.Println(cap(s1)) //10
}
- 如果多个slice指向相同底层数组,其中一个的值改变会影响全部
func main() {
a := []int{1, 2, 3, 4, 5}
s1 := a[2:5]
s2 := a[1:3]
fmt.Println(s1, s2) //[3 4 5] [2 3]
s1[0] = 9
fmt.Println(s1, s2) //[9 4 5] [2 9]
}
Reslice(从一个slice中获得另一个slice)
- Reslice时索引以被slice的切片为准
func main() {
a := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'}
sa := a[2:5]
sb := a[3:5] //在原数组a上取
sb2 := sa[1:3] //在切片sa上取
fmt.Println(string(sa)) //cde
fmt.Println(string(sb)) //de
fmt.Println(string(sb2)) //de
}
- 索引不可以超过被slice的切片的容量cap()值
- 索引越界不会导致底层数组的重新分配而是引发错误
func main() {
a := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'}
sa := a[2:5]
fmt.Println(len(sa), cap(sa)) //3 9
sb := a[3:5] //在原数组a上取
sb2 := sa[1:3] //在切片sa上取
sb3 := sa[3:5]
sb4 := sa[9:11] //超过了容量cap()值
fmt.Println(string(sa)) //cde
fmt.Println(string(sb)) //de
fmt.Println(string(sb2)) //de
fmt.Println(string(sb3)) //fg
fmt.Println(string(sb4)) //索引越界 slice bounds out of range
}
Append追加
- 可以在slice尾部追加元素
- 可以将一个slice追加在另一个slice尾部
- 如果最终长度未超过追加到slice的容量则返回原始slice
- 如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据
func main() {
s1 := make([]int, 3, 6)
fmt.Printf("%p\n", s1)
s1 = append(s1, 1, 2, 3)
fmt.Printf("%v %p\n", s1, s1)
s1 = append(s1, 1, 2, 3)
fmt.Printf("%v %p\n", s1, s1)
}
结果:
0xc420078000
[0 0 0 1 2 3] 0xc420078000
[0 0 0 1 2 3 1 2 3] 0xc42007e000 //注意此时超过容量了,重新分配了所以地址变了
- 在同一个底层数组上的修改会影响到所有的slice,但如果append后如果超出容量后,只会影响当前的slice
func main() {
a := []int{1, 2, 3, 4, 5}
s1 := a[2:5]
s2 := a[1:3]
fmt.Println(s1, s2) //[3 4 5] [2 3]
s2 = append(s2, 888, 888, 888, 888, 888, 888)
s1[0] = 9
fmt.Println(s1, s2) //[9 4 5] [2 3 888 888 888 888 888 888]
}
Copy 追加
func main() {
s1 := []int{1, 2, 3, 4, 5, 6}
s2 := []int{7, 8, 9}
copy(s1, s2) //把s2copy到s1中
fmt.Println(s1) //[7 8 9 4 5 6]
fmt.Println(s2) //[7 8 9]
}
func main() {
s1 := []int{1, 2, 3, 4, 5, 6}
s2 := []int{7, 8, 9}
copy(s2, s1)
fmt.Println(s1) //[1 2 3 4 5 6]
fmt.Println(s2) //[1 2 3]
}
把指定的值copy到指定的位置
func main() {
s1 := []int{1, 2, 3, 4, 5, 6}
s2 := []int{7, 8, 9}
copy(s1[2:4], s2[0:2])
fmt.Println(s1) //[1 2 7 8 5 6]
fmt.Println(s2) //[7 8 9]
}