Golang:在切片上使用附加时出现问题
Golang: Problems when using append on slice
我正在使用 golang。这是我的代码:
func main() {
quanPailie([]int{1, 2})
}
func quanPailie(nums []int) [][]int {
COUNT := len(nums)
//only one item
if COUNT == 1 {
return [][]int{nums}
}
insertItem(quanPailie(nums[:COUNT-1]), nums[COUNT-1])
return [][]int{}
}
func insertItem(res [][]int, insertNum int) {
fmt.Println("insertItem,res:", res, "insertNum", insertNum) //insertItem,res: [[1]] insertNum 2
for _, v := range res {
for i := 0; i < len(v); i++ {
fmt.Println("===before,v:", v)
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v)
fmt.Println("ccc", c)
}
}
}
让我很困惑的是输出:
===before,v: [1]
===after,v: [2]
为什么 v
的值发生了变化?希望可以有人帮帮我。非常感谢。
去游乐场:https://play.golang.org/p/wITYsGpX7U
编辑:
感谢icza的大力帮助,我想我已经理解了这个问题。
并且,这里有一个简单的代码来说明这个问题。
func test1() {
nums := []int{1, 2, 3}
_ = append(nums[:2], 4)
fmt.Println("test1:", nums)
//nums changes because the cap is big enought, the original array is modified.
}
func test2() {
nums := []int{1, 2, 3}
c := append(nums[:2], []int{4, 5, 6}...)
fmt.Println("test2:", nums)
fmt.Println("cc:", c)
//nums dont't change because the cap isn't big enought.
//a new array is allocated while the nums still points to the old array.
//Of course, the return value of append points to the new array.
}
这是有问题的代码:
fmt.Println("===before,v:", v)
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v)
你问为什么 v
在 2 个 Println()
语句之间变化。
因为您使用的是内置 append()
函数,引用其文档:
The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice.
因此,如果您附加到的切片有足够的空间(容量)来容纳您要附加的元素,则不会分配新切片,而是重新切片目标切片(这将使用相同的底层array) 和 append 将发生在其中。
让我们检查容量:
fmt.Println("===before,v:", v, cap(v))
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v, cap(v))
输出:
===before,v: [1] 2
===after,v: [2] 2
v
切片的容量为 2
。当 for
循环开始时,i=0
、v[:i]
是 v[:0]
,它是一个空切片(但容量为 2
),因此附加 1 或 2 个元素不会分配一个新的 array/slice,它将完成 "in place"。 "in place" 是 v
的第 0 个元素,因为 v[:i]
是 v[0:i]
的 shorthand。因此,元素将从共享的基础数组中的 v[0]
开始追加,因此由 v[0]
表示的元素将发生变化。
请注意,对切片进行切片会生成与原始切片共享其底层支持数组的切片(不会复制元素)。
如果您想避免这种情况,请使用或分配一个新切片,copy 原始内容并附加到新切片,例如:
src := []int{1, 2}
c := make([]int, len(src))
copy(c, src)
// Append something:
c = append(c, 3, 4)
fmt.Println(src) // [1 2] - src doesn't change
fmt.Println(c) // [1 2 3 4]
我正在使用 golang。这是我的代码:
func main() {
quanPailie([]int{1, 2})
}
func quanPailie(nums []int) [][]int {
COUNT := len(nums)
//only one item
if COUNT == 1 {
return [][]int{nums}
}
insertItem(quanPailie(nums[:COUNT-1]), nums[COUNT-1])
return [][]int{}
}
func insertItem(res [][]int, insertNum int) {
fmt.Println("insertItem,res:", res, "insertNum", insertNum) //insertItem,res: [[1]] insertNum 2
for _, v := range res {
for i := 0; i < len(v); i++ {
fmt.Println("===before,v:", v)
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v)
fmt.Println("ccc", c)
}
}
}
让我很困惑的是输出:
===before,v: [1]
===after,v: [2]
为什么 v
的值发生了变化?希望可以有人帮帮我。非常感谢。
去游乐场:https://play.golang.org/p/wITYsGpX7U
编辑:
感谢icza的大力帮助,我想我已经理解了这个问题。
并且,这里有一个简单的代码来说明这个问题。
func test1() {
nums := []int{1, 2, 3}
_ = append(nums[:2], 4)
fmt.Println("test1:", nums)
//nums changes because the cap is big enought, the original array is modified.
}
func test2() {
nums := []int{1, 2, 3}
c := append(nums[:2], []int{4, 5, 6}...)
fmt.Println("test2:", nums)
fmt.Println("cc:", c)
//nums dont't change because the cap isn't big enought.
//a new array is allocated while the nums still points to the old array.
//Of course, the return value of append points to the new array.
}
这是有问题的代码:
fmt.Println("===before,v:", v)
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v)
你问为什么 v
在 2 个 Println()
语句之间变化。
因为您使用的是内置 append()
函数,引用其文档:
The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice.
因此,如果您附加到的切片有足够的空间(容量)来容纳您要附加的元素,则不会分配新切片,而是重新切片目标切片(这将使用相同的底层array) 和 append 将发生在其中。
让我们检查容量:
fmt.Println("===before,v:", v, cap(v))
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v, cap(v))
输出:
===before,v: [1] 2
===after,v: [2] 2
v
切片的容量为 2
。当 for
循环开始时,i=0
、v[:i]
是 v[:0]
,它是一个空切片(但容量为 2
),因此附加 1 或 2 个元素不会分配一个新的 array/slice,它将完成 "in place"。 "in place" 是 v
的第 0 个元素,因为 v[:i]
是 v[0:i]
的 shorthand。因此,元素将从共享的基础数组中的 v[0]
开始追加,因此由 v[0]
表示的元素将发生变化。
请注意,对切片进行切片会生成与原始切片共享其底层支持数组的切片(不会复制元素)。
如果您想避免这种情况,请使用或分配一个新切片,copy 原始内容并附加到新切片,例如:
src := []int{1, 2}
c := make([]int, len(src))
copy(c, src)
// Append something:
c = append(c, 3, 4)
fmt.Println(src) // [1 2] - src doesn't change
fmt.Println(c) // [1 2 3 4]