3 回答
TA贡献2039条经验 获得超7个赞
不要分配append给除自身以外的任何东西。
正如您在问题中提到的,混淆是由于append既更改了底层数组又返回了一个新切片(因为长度可能会更改)。你会想象它复制了那个后备数组,但它没有,它只是分配一个slice指向它的新对象。由于i从不改变,所有这些附加值都会不断将 的值更改backingArray[12]为不同的数字。
将此与appending 与数组进行对比,后者每次分配一个新的文字数组。
所以是的,您需要先复制切片,然后才能对其进行处理。
func makeFromSlice(sl []int) []int {
result := make([]int, len(sl))
copy(result, sl)
return result
}
func main() {
i := make([]int, 0)
for ii:=0; ii<11; ii++ {
i = append(i, ii)
}
j := append(makeFromSlice(i), 100) // works fine
}
对切片文字行为进行了解释,因为如果追加超出支持数组的,则会分配一个新cap数组。这与切片文字无关,而与超出上限的内部原理有关。
a := []int{1,2,3,4,5,6,7}
fmt.Printf("len(a) %d, cap(a) %d\n", a, len(a), cap(a))
// len(a) 7, cap(a) 7
b := make([]int, 0)
for i:=1; i<8, i++ {
b = append(b, i)
} // b := []int{1,2,3,4,5,6,7}
// len(b) 7, cap(b) 8
b = append(b, 1) // any number, just so it hits cap
i := append(b, 100)
j := append(b, 101)
k := append(b, 102) // these work as expected now
TA贡献1877条经验 获得超6个赞
如果您需要切片的副本,除了复制切片之外别无他法。append除了 的第一个参数之外,您几乎不应该将 的结果分配给变量append。这会导致很难发现错误,并且会根据切片是否具有所需的容量而表现不同。
这不是通常需要的模式,但是对于所有这种性质的东西,如果您需要多次重复几行代码,那么您可以使用一个小的辅助函数:
func copyAndAppend(i []int, vals ...int) []int {
j := make([]int, len(i), len(i)+len(vals))
copy(j, i)
return append(j, vals...)
}
https://play.golang.org/p/J99_xEbaWo
TA贡献1856条经验 获得超5个赞
还有一种更简单的实现copyAndAppend函数的方法:
func copyAndAppend(source []string, items ...string) []string {
l := len(source)
return append(source[:l:l], items...)
}
在这里,我们只是确保源没有可用容量,因此强制复制。
- 3 回答
- 0 关注
- 167 浏览
添加回答
举报