When does Golang append() create a new slice?
根据内置API文档,当原始切片的容量不够大时,append()将重新分配并复制到新的数组块。
这里是一个(简化版)递归算法,用于创建字母组合(在本例中是布尔值)。字母表的成员(真、假)递归地添加到一个切片中,直到它的长度正确为止,此时它将通过通道发送。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package main import ( "fmt" ) func AddOption(c chan []bool, combo []bool, length int) { if length == 0 { fmt.Println(combo,"!") c <- combo return } var newCombo []bool for _, ch := range []bool{true, false} { newCombo = append(combo, ch) AddOption(c, newCombo, length-1) } } func main() { c := make(chan []bool) go func(c chan []bool) { defer close(c) AddOption(c, []bool{}, 4) }(c) for combination := range c { fmt.Println(combination) } } |
这里是这个代码的操场链接。在输出中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | [true true true true] ! [true true true false] ! [true true true false] [true true true false] [true true false true] ! [true true false false] ! [true true false false] [true true false false] [true false true true] ! [true false true false] ! [true false true false] [true false true false] [true false false true] ! [true false false false] ! [true false false false] [true false false false] [false true true true] ! [false true true false] ! [false true true false] [false true true false] [false true false true] ! [false true false false] ! [false true false false] [false true false false] [false false true true] ! [false false true false] ! [false false true false] [false false true false] [false false false true] ! [false false false false] ! [false false false false] [false false false false] |
号
以感叹号结尾的行是从addoption发送到通道的行。没有的是出现在另一边的东西(即在main()中)。很明显,通过通道发送的切片在发送后会被更改。
由于addoption在发送切片后立即返回,因此修改必须来自代码块
1 2 3 4 5 | var newCombo []bool for _, ch := range []bool{true, false} { newCombo = append(combo, ch) AddOption(c, newCombo, length-1) } |
但是,根据文档,append()应该返回一个新的切片(cap(combo)不够大)。根据这个答案,发送到addoption的切片描述符应该是一个副本;这不是真的吗?据我所知,作为addOption()的第二个参数发送的值要么是指向切片描述符的指针,要么是append()没有返回新切片。
(P)When EDOCX1 plogenic 0 create s a new slice,it doesn't create a slice that's just one larger than the slice before.它实际上创造了一个Slice,它比以前任何一个都大。请看这本法典:(p)字母名称(P)playground(p)(P)If you run this code,you see that the capacity initially double on every allocation;this strategy is of course changed for larger slice sizes.(p)
(P)You are confusing slice,the data type,with the actual representation.The Slice descriptor is composed of a pair of ints,one for len and one for cap,and a point to the underlying data.(p)(P)So,what append returns is indeed a new slice and what is passed to add option is indeed a copy of the slice descriptor.但是,从描述者到数据,观点的价值(对了解数据的问题)是相同的。(p)(P)Edit:here is a code snippet to illustrate my point:(p)字母名称(P)如果你跑了,你会得到:(p)字母名称(P)Because since EDOCX1 plography 1 common still has capacity,both EDOCX1 commercial 2 and EDOCX1 commercial 3 share the same data ptr.If you change the capacity to 4,it prints:(p)字母名称
(P)Ref:http://criticalindirection.com/2016/02/17/slice-with-a-pinch-of-salt/(p)(P)According to the link:(p)布尔奇1(P)This is quite different from the behavior of slices in other languages:(p)布尔奇1(P)The output of example mentioned,explains the behavior.(p)字母名称布尔奇1(P)Having multiple slices pointing to same underlying array,with frequent EDOCX1 plus 4-operations can get tricky.More on this in the link above.(p)