意外片追加行为 [英] unexpected slice append behaviour
问题描述
我今天在代码中遇到了奇怪的行为:当我在循环中追加元素
到 slice
,然后尝试根据循环结果创建新的切片
,最后追加
覆盖切片
从前面的追加
。
在这个特殊的例子中,它表示 sliceFromLoop
j
, g
和 h
切片的最后一个元素不是 100
, 101
和 102
但是...总是 102
!
第二个示例 - sliceFromLiteral
的行为如预期。
包主
$ b导入fmt
func create(iterations int)[] int {
a:= make([] int,0)
for i:= 0;我<迭代; i ++ {
a = append(a,i)
}
return a
}
func main(){
sliceFromLoop()
sliceFromLiteral()
}
func sliceFromLoop(){
fmt.Printf(**不按预期工作:** \ n\\ \\ n)
i:= create(11)
fmt.Println(initial slice:,i)
j:= append(i,100)
g:= append( i,101)
h:= append(i,102)
fmt.Printf(i:%v \ nj:%v\\'ng:%v\\\
h:%v\\\
,i,j,g,h)
}
func sliceFromLiteral(){
fmt.Printf(\\\
\\\
**按预期工作:* * \ n)
i:= [] int {0,1,2,3,4,5,6,7,8,9,10}
fmt.Println(initial slice: ,i)
j:= append(i,100)
g:= append(i,101)
h:= append(i,102)
fmt.Printf(i :%v \ nj:%v \\\
g:%v\\\
h:%v\\\
,i,j,g,h)
}
link to play.golang:
https://play.golang.org/p/INADVS3Ats
经过一些阅读,挖掘和试验后,我发现这个问题起源于 创建许多新切片的基本方法是什么在旧的和不担心改变旧切片的价值? 不要分配 正如你在问题中所提到的,混淆是由于 将它与 所以是的,你需要复制这个片段,然后才能使用它。 切片文字行为是由于新数组 为 ,如果append将超过支持数组的 I encountered weird behaviour in go code today: when I append In this particular example it means that Second example - link to play.golang:
https://play.golang.org/p/INADVS3Ats After some reading, digging and experimenting I found that this problem is originated in What's the idomatic way for creating many new slices based on old ones and not worrying about changing values of old slices? Don't assign As you mention in the question, the confusion is due to the fact that Contrast this to So yes, you need to copy the slice before you can work on it.
The slice literal behavior is explained because a new array is allocated if the append would exceed the
这篇关于意外片追加行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! slices
引用相同的底层数组
值,可以通过复制
slice
添加到新的,然后再添加任何东西,但它看起来相当......犹豫。
将
追加到除本身之外的其他任何东西上。
append
都会更改基础数组并返回一个新切片(因为长度可能会更改)。你可以想象它会复制支持数组,但它不会,它只是分配一个指向它的新的 slice
对象。由于 i
永不改变,所有这些附加操作都会将 backingArray [12]
的值更改为不同的数字。
append
添加到一个数组,每次都会分配一个新的数组。
$ b
func makeFromSlice(sl [] int)[] int {
result:= make([] int,len(sl))
copy(result,sl)
返回结果
}
func main(){
i:= make([] int,0)
for ii:= 0; II蛋白酶; 11; ii ++ {
i = append(i,ii)
}
j:= append(makeFromSlice(i),100)//正常工作
}
cap
。这与分片文字无关,并且与内部超出上限的内容无关。
a:= [ ] int {1,2,3,4,5,6,7}
fmt.Printf(len(a)%d,cap(a)%d \\\
,a,len(a) ,cap(a))
// len(a)7,cap(a)7
$ bbb:= 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)//任意数字,只要它达到上限
i:= append(b ,100)
j:= append(b,101)
k:= append(b,102)//这些工作如预期现在
elements
to slice
in loop and then try to create new slices
based on the result of the loop, last append
overrides slices
from previous appends
.sliceFromLoop
j
,g
and h
slice's last element are not 100
,101
and 102
respectively, but...always 102
!sliceFromLiteral
behaves as expected.package main
import "fmt"
func create(iterations int) []int {
a := make([]int, 0)
for i := 0; i < iterations; i++ {
a = append(a, i)
}
return a
}
func main() {
sliceFromLoop()
sliceFromLiteral()
}
func sliceFromLoop() {
fmt.Printf("** NOT working as expected: **\n\n")
i := create(11)
fmt.Println("initial slice: ", i)
j := append(i, 100)
g := append(i, 101)
h := append(i, 102)
fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h)
}
func sliceFromLiteral() {
fmt.Printf("\n\n** working as expected: **\n")
i := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println("initial slice: ", i)
j := append(i, 100)
g := append(i, 101)
h := append(i, 102)
fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h)
}
slices
referencing the same underlaying array
values and can be solved by copying slice
to new one before appending anything, however it looks quite... hesitantly.append
to anything other than itself.append
both changes the underlying array and returns a new slice (since the length might be changed). You'd imagine that it copies that backing array, but it doesn't, it just allocates a new slice
object that points at it. Since i
never changes, all those appends keep changing the value of backingArray[12]
to a different number.append
ing to an array, which allocates a new literal array every time.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
of the backing array. This has nothing to do with slice literals and everything to do with the internals of how exceeding the cap works.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