Golang append()什么时候创建一个新的切片? [英] When does Golang append() create a new slice?

查看:108
本文介绍了Golang append()什么时候创建一个新的切片?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据内置API文档,当原始片的容量不够大时,append()将重新分配并复制到一个新的数组块。



这是递归算法(的简化版本)用于创建字母组合(在这种情况下是布尔值)。字母(true,false)成员递归添加到切片,直到它是正确的长度,然后通过频道发送。

 包主要

导入(
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)
组合:=范围c {
fmt.Println(组合)
}
}

在这里是此代码的操场链接。在输出中:

  [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 false]
[true false true false]
[true false false true]!
[true false false false]!
[true false false]
[true 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在发送片段后立即返回,所以修改必须来自代码块

  var newCombo [] bool 
for _,ch:= range [] bool {true,false} {
newCombo = append(combo,ch)
AddOption(c,newCombo,length-1)
}

但是,根据文档,append()应该返回一个新的片(cap(combo)不够大)。根据这个答案,发送到AddOption的切片描述符应该是一个副本;这是不是真的?据我所知,无论是作为AddOption()的第二个参数发送的值是指向切片描述符的指针,还是append()都不会返回新的切片。

append()创建一个新的切片时,它不会创建比切片大一个的切片。

  package main 

importfmt

func main(){
var sl [] bool

for i:= 0;我< 100; i ++ {
sl = append(sl,true)
fmt.Println(cap(sl))
}
}
pre>

游乐场



如果您运行此代码,您会发现容量在每次分配时最初会加倍;这种策略当然会因更大的切片尺寸而发生变化。


According to the builtin api docs, append() will reallocate and copy to a new array block when the capacity of the original slice is not large enough.

Here is a (simplified version of) a recursive algorithm for creating combinations of an alphabet (in this case booleans). Members of the alphabet (true, false) are recursively added to a slice until it is the correct length, at which point it is sent over the channel.

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)
    }
}

Here is the playground link to this code. In the output:

[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]

Lines ending in an exclamation mark are those sent into the channel from AddOption. Those without are what emerges on the other side (i.e. in main()). It is clear that the slices send over the channel are changed after they are sent.

Since AddOption returns immediately after sending the slice, the modification has to come from the code block

var newCombo []bool
for _, ch := range []bool{true, false} {
    newCombo = append(combo, ch)
    AddOption(c, newCombo, length-1)
}

But, according to the docs, append() should return a new slice (cap(combo) is not large enough). According to this answer, the slice descriptor sent to AddOption should be a copy; is that not true? As far as I can tell, either the value sent as the second argument to AddOption() is either a pointer to a slice descriptor, or append() is not returning a new slice.

解决方案

When append() creates a new slice, it doesn't create a slice that's just one larger than the slice before. It actually creates a slice that is already a couple of elements larger than the previous one. Have a look at this code:

package main

import "fmt"

func main() {
    var sl []bool

    for i := 0; i < 100; i++ {
        sl = append(sl, true)
        fmt.Println(cap(sl))
    }
}

Playground

If you run this code, you see that the capacity initially doubles on every allocation; this strategy is of course changed for larger slice sizes.

这篇关于Golang append()什么时候创建一个新的切片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆