【发布时间】:2015-02-18 12:24:54
【问题描述】:
下面的程序有意外的输出。
func main(){
s:=[]int{5}
s=append(s,7)
s=append(s,9)
x:=append(s,11)
y:=append(s,12)
fmt.Println(s,x,y)
}
输出:[5 7 9] [5 7 9 12] [5 7 9 12]
为什么x12的最后一个元素是?
【问题讨论】:
下面的程序有意外的输出。
func main(){
s:=[]int{5}
s=append(s,7)
s=append(s,9)
x:=append(s,11)
y:=append(s,12)
fmt.Println(s,x,y)
}
输出:[5 7 9] [5 7 9 12] [5 7 9 12]
为什么x12的最后一个元素是?
【问题讨论】:
切片只是数组部分的一个窗口,它没有特定的存储空间。
这意味着如果数组的同一部分有两个切片,则两个切片必须“包含”相同的值。
这正是这里发生的事情:
append 时,您会在大小为 2 的基础数组上获得一个大小为 2 的新切片。append 时,您会得到一个大小为3 的新切片,但底层数组的大小为4(append 通常会分配比立即需要的空间更多的空间,因此它不会t 需要在每次追加时分配)。append 不需要新数组。所以x 和y 都将使用与前面的切片s 相同的底层数组。你在这个数组的同一个槽中写入11 然后12,即使你得到两个不同的切片(记住,它们只是窗口)。您可以通过在每次追加后打印切片的容量来检查:
fmt.Println(cap(s))
如果你想在x 和y 中有不同的值,你应该做一个copy,例如这样:
s := []int{5}
s = append(s, 7)
s = append(s, 9)
x := make([]int,len(s))
copy(x,s)
x = append(x, 11)
y := append(s, 12)
fmt.Println(s, x, y)
这里的另一种解决方案可能是强制s 切片后面的数组容量不大于所需的容量(从而确保append 后面的两个有使用新数组):
s := []int{5}
s = append(s, 7)
s = append(s, 9)
s = s[0:len(s):len(s)]
x := append(s, 11)
y := append(s, 12)
fmt.Println(s, x, y)
【讨论】:
dystroy 很好地解释了它。我喜欢为行为添加视觉解释。
切片只是数组段的描述符。它由指向数组的指针 (ptr)、段的长度 (len) 和容量 (cap) 组成。
+-----+
| ptr |
|*Elem|
+-----+
| len |
|int |
+-----+
| cap |
|int |
+-----+
所以,代码的解释如下;
func main() {
+
|
s := []int{5} | s -> +-----+
| []int | ptr +-----> +---+
| |*int | [1]int| 5 |
| +-----+ +---+
| |len=1|
| |int |
| +-----+
| |cap=1|
| |int |
| +-----+
|
s = append(s,7) | s -> +-----+
| []int | ptr +-----> +---+---+
| |*int | [2]int| 5 | 7 |
| +-----+ +---+---+
| |len=2|
| |int |
| +-----+
| |cap=2|
| |int |
| +-----+
|
s = append(s,9) | s -> +-----+
| []int | ptr +-----> +---+---+---+---+
| |*int | [4]int| 5 | 7 | 9 | |
| +-----+ +---+---+---+---+
| |len=3|
| |int |
| +-----+
| |cap=4|
| |int |
| +-----+
|
x := append(s,11) | +-------------+-----> +---+---+---+---+
| | | [4]int| 5 | 7 | 9 |11 |
| | | +---+---+---+---+
| s -> +--+--+ x -> +--+--+
| []int | ptr | []int | ptr |
| |*int | |*int |
| +-----+ +-----+
| |len=3| |len=4|
| |int | |int |
| +-----+ +-----+
| |cap=4| |cap=4|
| |int | |int |
| +-----+ +-----+
|
y := append(s,12) | +-----> +---+---+---+---+
| | [4]int| 5 | 7 | 9 |12 |
| | +---+---+---+---+
| |
| +-------------+-------------+
| | | |
| s -> +--+--+ x -> +--+--+ y -> +--+--+
| []int | ptr | []int | ptr | []int | ptr |
| |*int | |*int | |*int |
| +-----+ +-----+ +-----+
| |len=3| |len=4| |len=4|
| |int | |int | |int |
| +-----+ +-----+ +-----+
| |cap=4| |cap=4| |cap=4|
| |int | |int | |int |
+ +-----+ +-----+ +-----+
fmt.Println(s,x,y)
}
【讨论】: