英文:
Why append slice in Go change the original slice?
问题
我有这段代码:
// 输入参数是 A := []int{3, 4, 5, 3, 7}
func someFunc(A []int) int {
...
ways := 0
i := 0
for i < len(A) {
if i+1 == len(A) || i == len(A) {
fmt.Println("break")
break
}
tempA := A // 通过值复制切片
fmt.Println("A: ", A)
fmt.Println("tempA: ", A)
fmt.Println()
newArr = remove(tempA, i)
if isAesthetic(newArr) {
ways++
}
i++
}
...
}
func remove(slice []int, s int) []int {
return append(slice[:s], slice[s+1:]...)
}
控制台输出:
A: [3 4 5 3 7]
tempA: [3 4 5 3 7]
A: [4 5 3 7 7]
tempA: [4 5 3 7 7]
A: [4 3 7 7 7]
tempA: [4 3 7 7 7]
A: [4 3 7 7 7]
tempA: [4 3 7 7 7]
变量 A
在我只是通过值复制到 tempA
中时也发生了变化。而且这里使用的是 append()
函数,为什么用于追加 tempA
的切片也发生了变化?
英文:
I have this code:
// The input param is A := []int{3, 4, 5, 3, 7}
func someFunc(A []int) int {
...
ways := 0
i := 0
for i < len(A) {
if i+1 == len(A) || i == len(A) {
fmt.Println("break")
break
}
tempA := A // copy the slice by value
fmt.Println("A: ", A)
fmt.Println("tempA: ", A)
fmt.Println()
newArr = remove(tempA, i)
if isAesthetic(newArr) {
ways++
}
i++
}
...
}
func remove(slice []int, s int) []int {
return append(slice[:s], slice[s+1:]...)
}
Cosole output:
A: [3 4 5 3 7]
tempA: [3 4 5 3 7]
A: [4 5 3 7 7]
tempA: [4 5 3 7 7]
A: [4 3 7 7 7]
tempA: [4 3 7 7 7]
A: [4 3 7 7 7]
tempA: [4 3 7 7 7]
The variable A
also changes while I just copy it by value into tempA
. And also it is append()
function, why the slice that used to append tempA
also changed?
答案1
得分: 3
[]T
类型的切片变量,也称为切片头部,描述了一个连续的数组部分。它与数组数据分开存储。
你可以将其想象为一个包含长度和指向数组某个元素的指针的结构体(不一定是第一个元素)。
当你给一个切片变量赋值时,实际上是在赋值切片头部所持有的长度和指针。所以 tempA
最终引用的是与 A
相同的底层数组。然后对其中任意一个进行索引操作都会访问相同的底层数组元素。
推荐阅读:https://blog.golang.org/slices
英文:
A slice variable of type []T
, also called slice header, describes a contiguous section of a backing array. It is stored separately from the array data.
You can imagine it as a struct containing the length and a pointer to a certain item of the array (not necessarily the first one).
When you assign the value of a slice variable, you are actually assigning the length and pointer held by the slice header. So tempA
ends up referencing the same backing array as A
. Then indexing either will access the same underlying array item.
Recommended reading: https://blog.golang.org/slices
答案2
得分: 3
类型[]T
是具有类型为T
的元素的切片
。那么,什么是切片
呢?
切片是数组片段的描述符。它由指向数组的指针、片段的长度和容量(片段的最大长度)组成。
左侧的矩形是切片描述符。描述符有3个字段,即指向数组的指针、指向的数组片段的长度和容量。现在,指针指向右侧实际存储元素的后备数组。
假设你有一个切片:
x := make([]byte, 5, 5)
那么它将指向一个后备数组[5]byte
,你也可以在图像中看到。
现在,如果你执行:
y := x
以为这样会复制,但实际上不会。它只会创建一个新的切片描述符,指向与x
指向的相同的后备数组。
因此,有一个名为copy的内置函数可以帮助你复制(正好是你想要的)。
copy内置函数将源切片的元素复制到目标切片中。
使用copy
函数,你还会得到一个新的后备数组,指向你的目标切片。
要了解更多关于切片的信息,请阅读这篇文章。
英文:
The type []T
is a slice
with elements of type T
. What is a slice
, then?
> A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).
The rectangle on left is the slice descriptor. The descriptor has 3 fields i.e., a pointer to the array, length, and capacity of array segment it is pointing to. Now, the pointer is pointing to a backing array on the right that actually stores the elements.
Suppose, you have a slice:
x := make([]byte, 5, 5)
Then it'd point to a backing array [5]byte
as you can also see in the image.
Now, if you do:
y := x
thinking that would copy, but it wouldn't. It'd just create a new slice descriptor pointing to the same backing array that x
was pointing to.
Hence, there's a built-in called copy which would help you copy (exactly what you want)
The copy built-in function copies elements from a source slice into a destination slice.
With copy
you also get a new backing array that your destination site is pointing to.
To know more about slices, read this.
答案3
得分: 0
你需要使用copy
函数:
package main
import "fmt"
func main() {
a := []int{3, 4, 5, 3, 7}
// 不好的做法
b := a
// 好的做法
c := make([]int, len(a))
copy(c, a)
// 修改了b和a!
b = append(b[:1], b[2:]...)
// c保持不变,a被破坏了
// [3 5 3 7 7] [3 5 3 7] [3 4 5 3 7]
fmt.Println(a, b, c)
}
https://golang.org/pkg/builtin#copy
英文:
You need to utilize the copy
function:
package main
import "fmt"
func main() {
a := []int{3, 4, 5, 3, 7}
// bad
b := a
// good
c := make([]int, len(a))
copy(c, a)
// CHANGES b and a!
b = append(b[:1], b[2:]...)
// c stays the same, a is messed up
// [3 5 3 7 7] [3 5 3 7] [3 4 5 3 7]
fmt.Println(a, b, c)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论