slice的属性

  1. 切片(slice)是建立在数组之上的更方便,更灵活,更强大的数据结构。切片并不存储任何元素而只是对现有数组的引用。

  2. 切片的长度是指切片中元素的个数。切片的容量是指从切片的起始元素开始到其底层数组中的最后一个元素的个数。

那么问题来了,几个不同的切片指向同一个数组,如果数组的值被改变会出现什么神奇的操作?

问题实例

slice的cap是怎么增长的

  1. 参考文章:How does Go slice capacity change on append? [duplicate]

  2. 有兴趣也可以看看golang的源码实现,在$GOPATH/src/runtime/slice.go

slice的结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

type slice struct {

	array unsafe.Pointer

	len   int

	cap   int

}

多次append造成的数据错误

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

package main

import "fmt"

func main() {

	temp := []int{}

	temp = append(temp, 1)

	printSlice("temp", temp)

	temp = append(temp, 2)

	printSlice("temp", temp)

	temp = append(temp, 3)

	// temp := []int{1, 2, 3}

	printSlice("temp", temp)

	temp2 := append(temp, 4)

	printSlice("temp2", temp2)

	temp4 := append(temp, 5, 6)

	printSlice("temp4", temp4)

	temp3 := append(temp, 5)

	printSlice("temp3", temp3)

	printSlice("temp2", temp2)

}

func printSlice(valName string, s []int) {

	fmt.Printf("%s %p %v, len: %d, cap: %d\n", valName, s, s, len(s), cap(s))

}

结果


temp 0xc00000a0d8 [1], len: 1, cap: 1

temp 0xc00000a120 [1 2], len: 2, cap: 2

temp 0xc0000123a0 [1 2 3], len: 3, cap: 4

temp2 0xc0000123a0 [1 2 3 4], len: 4, cap: 4

temp4 0xc00000e440 [1 2 3 5 6], len: 5, cap: 8

temp3 0xc0000123a0 [1 2 3 5], len: 4, cap: 4

temp2 0xc0000123a0 [1 2 3 5], len: 4, cap: 4

这个示例的slice的cap是逐步增长的,可以看出temp在不停的append的时候,cap的大小到达了4,然后temp2在此基础上继续append,但是temp的len=3,所以temp2和temp所指向的array是同一个;在temp3的时候,和temp2遇到了同样的情况,temp的len=3,所以temp3和temp所指向的array是同一个。那好戏就开始了,在append构造出temp3时,会直接覆盖temp2的第四个element,最后,我们再次使用temp2的时候发现数据被改变了。