在Go的slice tricks wiki和Go库(例如,this example)上,您有时会看到如下代码,将一个切片复制到新的支持数组中.

// In a library at the end of a function perhaps...
return append(whateverSlice[:0:0], whateverSlice...)

// In an assignment, as in the wiki example...
b = append(a[:0:0], a...)

以下是我认为我理解的内容:

  • 作为append的第二个参数的切片中的所有项都被复制到新的支持数组中.
  • 在将第一个参数设置为append时,代码使用a full slice expression.(我们可以将第一个参数重写为a[0:0:0],但如果省略,将提供第一个0.我认为这与这里更广泛的含义无关.)
  • 基于the spec,生成的切片应该与原始切片具有相同的类型,并且其长度和容量应该为零.
  • (同样,不直接相关,但我知道你可以用copy而不是append,而且读起来要清楚得多.)

然而,我仍然不能完全理解why语法append(someSlice[:0:0], someSlice...)创建一个新的后备array.我最初也很困惑,为什么append操作没有扰乱(或截断)原始切片.

现在让我来猜一猜:

  • 我假设所有这些都是必要的和有用的,因为如果您只分配newSlice := oldSlice,那么对一个的更改将反映在另一个中.通常,你不会想要这样的.
  • 因为我们不将append的结果赋给原始切片(这在围棋中是正常的),所以原始切片不会发生任何变化.它不会以任何方式被截断或更改.
  • 因为anySlice[:0:0]的长度和容量都是零,所以如果要将anySlice的元素赋给结果,GO必须创建一个新的支持array.这why是一个新的后备数组被创建吗?
  • 如果anySlice...没有元素,会发生什么?snippet on the Go Playground表示,如果您在空切片上使用此追加技巧,则副本和原始切片最初具有相同的支持array.(Edit:作为a commenter explains,我误解了这段代码.该代码片段显示,这两个项目最初是相同的,但却是neither has a backing array yet.它们最初都指向一个通用的零值.)因为这两个片的长度和容量都是零,所以只要您向其中一个片添加任何东西,that one就会得到一个新的支持array.因此,我想,效果仍然是一样的.也就是说,在append复制之后,两个切片不能相互影响.
  • other playground snippet表明,如果一个切片具有多于零个元素,则append复制方法立即导致新的支持array.在这种情况下,可以说,产生的两个切片立即分离.

我可能对此担心得太多了,但我希望能更全面地解释whyappend(a[:0:0], a...)的诀窍是如何起作用的.

推荐答案

因为anySlice[:0:0]的长度和容量都为零,所以如果要将anySlice的元素赋给结果,Go必须创建一个新的支持array.这就是创建新的后备数组的原因吗?

因为运力是0,是的.


https://pkg.go.dev/builtin@go1.19.3#append

如果它有足够的容量,则重新许可目的地以容纳新元素.如果没有,将分配一个新的底层array.

  • 对于非空片,cap=0是不够的,需要分配新的array.

Go相关问答推荐

有没有办法通过Go cmdline或IDE(IntelliJ)找出我的 struct 实现了什么接口?

MaybeReadByte对通道的使用如何在Go中提供随机行为?

创建服务时云运行触发器执行失败

调用库和直接操作效率有区别吗?

使用golang sqlc中的引用参数

Caddy服务器try 打开端口80而不是8090.

Go struct 匿名字段是公开的还是私有的?

尽管存在 WaitGroup,Goroutines 似乎被打断了

在密钥不存在时处理 PATCH 部分更新

是否可以从 golang 中的参数推断类型?

将值发送到 Channel 并在就绪时读取输出

没有任务角色的 AWS CDK ECS 任务定义

我在 go 中制作的递归函数有什么问题?

Golang 工作池实现意外工作

Go 并发、goroutine 同步和关闭通道

使用 delve 在容器中调试 Golang:container_linux.go:380:启动容器进程导致:exec:/dlv:stat /dlv:没有这样的文件或目录

Go 导入范围查找 protobuf 类型

为什么 go.mod 中的所有依赖都是间接的?

递归数据 struct 解组在 Go Lang Protobuf 中给出错误无法解析无效的线格式数据

如何在程序退出时使用 golang 删除文件?