Go 切片

切片Slice

切片本身并不是数组,是指向底层的数组,类似指针。其作为变长数组的替代方案,可以关联底层数组的局部或全部。同时这是一个引用类型,可以直接传教或者从底层数组获取生成。和数组一样,可以使用len()来获取元素个数,cap()获取容量。一般使用mark()进行创建,而不是new ()

如果多个slice指向相同的底层数组,其中一个的值改变会影响到全部

1
make([]T, len, cap)

其中cap是可以省略的,默认为与len()值相同

简单例子

1
2
var a []int
fmt.Println(a)

输出

1
[]

取元素

取前/后n位元素

1
2
3
4
5
6
func sliceF2() {
a := [10]int{1, 2, 4, 5, 6, 7, 8, 9, 10}
fmt.Println(a)
s1 := a[5:10]
fmt.Println(s1)
}

输出

1
2
[1 2 4 5 6 7 8 9 10 0]
[7 8 9 10 0]

包含起始索引,不包含结尾的索引

可以简化下

1
2
3
4
-  s1 := a[5:10]
+ s1 := a[5:]
// 或者
+ s1 := a[5:len(a)]

往前面取,索引从0~4

1
s1 := a[:5]

make

1
2
3
4
5
func sliceF3() {
// 类型,元素个数,容量
s1 := make([]int, 3, 10)
fmt.Println(len(s1), cap(s1))
}

当元素个数小于等于容量时,不会进行扩容。当大于当前容量时,会分配长度位20且连续的内存块。每次超过时,容量值会翻倍,10->20->40。

容量默认为元素格式

Reslice

Reslice 时索引以被slice的切片为准,索引不可以超过被slice的切片容量cap()值,索引越界不会导致底层数组的重新分配而是引发错误

1
2
3
4
5
6
7
8
9
10
11
12
func sliceF4() {
a := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'}
sa := a[2:5]
// 在sa的范围内
sb := sa[0:2]
// 超出sa的范围,但后面的内容是连续的
sc := sa[3:5]
fmt.Println(string(a))
fmt.Println(string(sa), len(sa), cap(sa))
fmt.Println(string(sb))
fmt.Println(string(sc))
}

输出

1
2
3
4
abcdefghijk
cde 3 9
cd
fg

sa 从'c'的位置开始,一直到a结束,是一个连续的,所分配的最大容器是 9

Append

在slice尾部追加元素,可以将一个slice追加到另一个slice的尾部,如果最终长度未超过追加到slice的容量则返回原始slice。如果超过,则将会重新分配数组并拷贝原始数据

1
2
3
4
5
6
func sliceF5() {
s1 := make([]int, 3, 6)
fmt.Printf("%p\n", s1)
s1 = append(s1, 1, 2, 3)
fmt.Printf("%v %p\n", s1, s1)
}

输出

1
2
0xc0000d6030
[0 0 0 1 2 3] 0xc0000d6030

超出时,重新分配并拷贝原始数据

1
2
3
4
5
6
7
8
func sliceF5() {
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)
}

输出

1
2
3
0xc0000d6030
[0 0 0 1 2 3] 0xc0000d6030
[0 0 0 1 2 3 1 2 3] 0xc000086060

同时指向的影响

多个slice指向同一个底层数组,在操作数组时,会影响到所有关联的slice

1
2
3
4
5
6
7
8
func sliceF6() {
a := []int{1, 2, 3, 4, 5, 6}
s1 := a[0:4]
s2 := a[0:3]
fmt.Println(s1, s2)
s1[1] = 123go
fmt.Println(s1, s2)
}

输出

1
2
[1 2 3 4] [1 2 3]
[1 123 3 4] [1 123 3]

但对slice2进行append操作,并超过其cap()值时,之后的操作就不会影响到slice2

1
2
3
4
5
6
7
8
9
func sliceF6(){
a := []int{1, 2, 3, 4, 5, 6}
s1 := a[0:4]
s2 := a[0:3]
fmt.Println(s1, s2)
+ s2 = append(s2, 1, 1, 1, 1, 1, 1, 1, 1)
a[1] = 123
fmt.Println(s1, s2)
}

输出

1
2
[1 2 3 4] [1 2 3]
[1 123 3 4] [1 2 3 1 1 1 1 1 1 1 1]

Copy

1
2
3
4
5
6
func sliceF8() {
s1 := []int{1, 2, 3, 4, 5, 6}
s2 := []int{7, 8, 9}
copy(s2, s1)
fmt.Println(s2)
}

输出

1
[1 2 3]

s2 中只有3个元素,将会copy前3个元素

只copy s1中的一部分,s1[0:2]是一个新的slice

1
2
+ copy(s2, s1[0:2])
- copy(s2, s1)

输出

1
[1 2 9]

或者只是替换其中一部分

1
2
+ copy(s2[1:2], s1[0:2])
- copy(s2, s1)

输出

1
[7 1 9]

得到一个完整的数组

1
2
3
4
5
6
7
8
9
10
11
s1 := []int{1, 2, 3, 4, 5, 6}
s3 := s1
s4 := s1[0:]
s5 := s1[0:len(s1)]
s6 := s1[:len(s1)]
s7 := s1[:]
fmt.Println(s3)
fmt.Println(s4)
fmt.Println(s5)
fmt.Println(s6)
fmt.Println(s7)

输出

1
2
3
4
5
[1 2 3 4 5 6]
[1 2 3 4 5 6]
[1 2 3 4 5 6]
[1 2 3 4 5 6]
[1 2 3 4 5 6]
- the End -
0%