考虑这段代码:
package main
import (
"fmt"
)
func main() {
fmt.Println(Part(11))
}
func Part(n int) string {
enumResult := [][]int{}
enum(n, n, []int{}, &enumResult)
fmt.Println(enumResult)
fmt.Println(40, enumResult[40])
return ""
}
var abc int = 0
func enum(n int, top int, pre []int, result *[][]int) {
var i int
if n > top {
i = top
} else {
i = n
}
for ; i > 0; i-- {
tempResult := append(pre, i)
if n-i == 0 {
/* if tempResult[0] == 3 && tempResult[1] == 3 && tempResult[2] == 3 && tempResult[3] == 2 {
tempResult = append(tempResult, 12345)
}*/
fmt.Println(abc, tempResult)
abc++
*result = append(*result, tempResult)
} else {
enum(n-i, i, tempResult, result)
}
}
}
当我运行此代码时
我将'[3,3,3,2]'附加到'enumResult'
但是,如果我检查'enumResult'的值,则会出现'[3,3,3,1]'
它的索引是40 => enumResult [40] (其他值是正确的)
我不知道为什么会这样 你能解释一下为什么吗?
答案 0 :(得分:0)
问题确实归因于append
。
append
有两件事。首先,append
不一定要复制记忆。由于spec指定:
如果s的容量不足以容纳附加值, append分配一个适合的新的,足够大的底层数组 现有的切片元素和附加值。 ,否则下, 追加重新使用基础数组。
如果您不清楚,这可能会导致意外行为。一个游乐场示例:https://play.golang.org/p/7A3JR-5IX8o
第二部分是,当append
复制内存时,它会增加切片的容量。但是,它不会仅仅增加1.游乐场示例:https://play.golang.org/p/STr9jMqORUz
切片的append
增长多少未记录,并被视为实施细节。但是直到Go 1.10,它遵循这条规则:
切片增长一倍,直到大小1024,之后它们会增长 每次25%。
请注意,启用竞赛检测器时,可能会发生变化。增长切片的代码位于$GOROOT/src/runtime/slice.go
函数中的growslice
。
现在回到这个问题。现在应该很清楚,由于之前append
的切片增长,您的代码从具有足够容量的相同切片中执行append
。要解决此问题,请创建一个新切片并复制内存。
tempResult := make([]int,len(pre)+1)
copy(tempResult,pre)
tempResult[len(pre)] = i