golang 切片裁剪后改变原切片,导致重新赋值?
对比以下两种操作方式:
第一种
package main
import "fmt"
func main() {
t := []int{1, 2, 4, 5}
a := t[:2]
b := t[2:]
fmt.Println(t)
fmt.Println(a)
fmt.Println(b)
a = append(a, 3)
fmt.Println(t)
fmt.Println(a)
fmt.Println(b)
}
输出结果:
[1 2 4 5]
[1 2]
[4 5]
[1 2 3 5]
[1 2 3]
[3 5]
第二种
package main
import "fmt"
func main() {
t := []int{1, 2, 4, 5}
a := t[:2:2] // 细微处改变
b := t[2:]
fmt.Println(t)
fmt.Println(a)
fmt.Println(b)
a = append(a, 3)
a = append(a, b...)
fmt.Println(t)
fmt.Println(a)
fmt.Println(b)
}
输出结果:
[1 2 4 5]
[1 2]
[4 5]
[1 2 4 5]
[1 2 3]
[4 5]
第二种与第一种的细微处改变唯一的区别就是从 t
裁剪出 a
的时候,指定了cap
:
a := t[:2:2]
第一种未指定的情况下,a
初始化cap
和t
是一致的,但是对于b
初始化出来的cap
和len
一致,都是2
。但是这里如果指定的cap
和t
保持一致,依旧会有问题,结果不符合预期。
想请教一下各位导致这种情况的原因是什么,是否能找到相关的官方文档看一下。
这个问题具体来源于我希望在slice指定位置插入一个元素:
package main
import "fmt"
func main() {
t := []int{1, 2, 4, 5}
r := append(append(t[:2], 3), t[2:]...)
fmt.Println(r) // 结果:[1 2 3 3 5],不符合预期
}
回复
1个回答

test
2024-07-13
package main
import "fmt"
func main() {
t := []int{1, 2, 4, 5}
fmt.Println(t[2:]) // [4 5]
s := append(t[:2], 3) // 其实就是这个操作前后,导致了原有的 s 变化
fmt.Println(t[2:]) // [3 5]
r := append(s, t[2:]...)
fmt.Println(r) // 结果:[1 2 3 3 5],不符合预期
}
首先 对于 s[start:end] 这样的操作,在操作完成之后,还是指向原来的 slice,这点在官方文档中有体现:https://go.dev/ref/spec#Slice...
其实,最关键的一个理解是,slice[1:3] 这样类似的切分操作,不要理解为是将原来的slice 进行取出,重新赋值;而理解成一个视图,只是看到了一部分。
最后,如何在 slice 插入一个元素,可以尝试这样解决
r := append([]int{}, t[:2]...)
r = append(r, 3)
r = append(r, t[2:]...)
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容