英文:
Go slice overwrite
问题
这是源代码:
package main
func main() {
testSlice()
}
func testSlice() {
slice := make([]int, 0)
//slice = append(slice, 1) ①
//slice = append(slice, 1, 2) ②
//slice = append(slice, 1, 2, 3) ③
//slice = append(slice, 1, 2, 3, 4) ④
slice = append(slice, 1, 2, 3, 4, 5) ⑤
//slice = append(slice, 1, 2, 3, 4, 5, 6) ⑥
slice2 := append(slice, 1)
slice3 := append(slice, 2)
for _, i := range slice2 {
print(i)
}
println()
for _, i := range slice3 {
print(i)
}
}
期望输出:
123451
123452
实际输出:
123452
123452
除了 ⑤ 之外,①~⑥ 的输出都是符合预期的。但为什么 ⑤ 中 slice3
覆盖了 slice2
?
这个原因与指针或切片的调整大小有关吗?
英文:
Here is the source code:
package main
func main() {
testSlice()
}
func testSlice() {
slice := make([]int, 0)
//slice = append(slice, 1) ①
//slice = append(slice, 1, 2) ②
//slice = append(slice, 1, 2, 3) ③
//slice = append(slice, 1, 2, 3, 4) ④
slice = append(slice, 1, 2, 3, 4, 5) ⑤
//slice = append(slice, 1, 2, 3, 4, 5, 6) ⑥
slice2 := append(slice, 1)
slice3 := append(slice, 2)
for _, i := range slice2 {
print(i)
}
println()
for _, i := range slice3 {
print(i)
}
}
Expected output:
123451
123452
Actual output:
123452
123452
The output of ①~⑥ except ⑤ is as expected. But why ⑤ slice3
overwrites slice2
?
Is the reason related to pointer or slice resize?
答案1
得分: 1
请查看这个 Stack Overflow 回答,在阅读我回答的其余部分之前,它提供了关于切片(slice)的非常有帮助的解释。通过打印出实际的切片头部,可能更容易理解正在发生的情况。请参考以下示例代码(以及Go Playground):
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
testSlice()
}
func testSlice() {
slice := make([]int, 0)
slice = append(slice, 1, 2, 3, 4, 5)
fmt.Printf("%+v\n", (*reflect.SliceHeader)(unsafe.Pointer(&slice)))
slice2 := append(slice, 1)
fmt.Printf("%+v\n", (*reflect.SliceHeader)(unsafe.Pointer(&slice2)))
slice3 := append(slice, 2)
fmt.Printf("%+v\n", (*reflect.SliceHeader)(unsafe.Pointer(&slice3)))
for _, i := range slice2 {
print(i)
}
println()
for _, i := range slice3 {
print(i)
}
}
这将打印出类似以下的内容:
&{Data:824634441776 Len:5 Cap:6}
&{Data:824634441776 Len:6 Cap:6}
&{Data:824634441776 Len:6 Cap:6}
这表明所有变量 slice
、slice2
和 slice3
都指向相同的数据(Data
是指向切片第一个元素的指针),但切片头部本身是不同的。当执行 append
操作时,您正在修改所有变量共享的底层切片,并将新的切片头部存储到新的变量中。slice2
和 slice3
的切片头部都指向相同的数据切片,因此当您执行 slice3
的 append
操作时,您正在覆盖所有变量共享的底层切片中的第6个元素。
英文:
Check out this SO answer for a really helpful explanation of what a slice actually is before reading the rest of my answer. It might be easier to understand what's going on by printing out the actual slice headers. See the following example code (and go playground):
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
testSlice()
}
func testSlice() {
slice := make([]int, 0)
slice = append(slice, 1, 2, 3, 4, 5)
fmt.Printf("%+v\n", (*reflect.SliceHeader)(unsafe.Pointer(&slice)))
slice2 := append(slice, 1)
fmt.Printf("%+v\n", (*reflect.SliceHeader)(unsafe.Pointer(&slice2)))
slice3 := append(slice, 2)
fmt.Printf("%+v\n", (*reflect.SliceHeader)(unsafe.Pointer(&slice3)))
for _, i := range slice2 {
print(i)
}
println()
for _, i := range slice3 {
print(i)
}
}
This will print something like this:
&{Data:824634441776 Len:5 Cap:6}
&{Data:824634441776 Len:6 Cap:6}
&{Data:824634441776 Len:6 Cap:6}
This shows that all variables slice
, slice2
, and slice3
are pointing at the same data (Data
which is a pointer to the first element of the slice) but the slice headers themselves are different. When you're performing your append
s, you are modifying the underlying slice shared by all the variables, and storing new slice headers into new variables. The slice headers for slice2
and slice3
are looking at the same slice of data, so when you come along and perform your append for slice3
, you're overwriting the 6th element in the underlying slice that is shared by all the variables.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论