最近在看 Golang,请教如何避免 Slice 的坑

2018-11-07 13:32:06 +08:00
 goofool

比如 slice 的 append,按我的理解:

1,扩容就生成新的底层数组,修改新的 slice 不会影响原来底层数组;

2,不扩容就不会生成新的数组,修改新的 slice 会修改原来的底层数组;

觉得这种问题很容易掉坑,求教有什么好习惯可以避免掉坑。

3826 次点击
所在节点    Go 编程语言
21 条回复
dongisking
2018-11-07 13:37:28 +08:00
另外一个坑
cheshire
2018-11-07 13:37:30 +08:00
初始化的时候能知道大小最好,不然的话指定一个比较大的 capacity
goofool
2018-11-07 13:47:44 +08:00
@dongisking 这个结果是唯一的吧,会有第二种情况吗
goofool
2018-11-07 13:49:22 +08:00
@cheshire 如果 slice 作为参数接收到的咋办呢
brucewuio
2018-11-07 14:10:36 +08:00
其实《 The Go Programming Language 》 说的挺清楚的 上面也说尽量用数组的抽象 slice 很少直接用数组 加操作直接 append 减操作就[x:y] 截取
anonymous256
2018-11-07 14:13:21 +08:00
这里有个不错的坑,参见: https://www.golangtc.com/t/5565344ab09ecc3d42000026

```golang
var dynaArr []string
dynaArr = append(dynaArr, "one")
dynaArr = append(dynaArr, "two")
dynaArr = append(dynaArr, "three")
fmt.Println(dynaArr)
```
这样写就好
sirgod
2018-11-07 14:21:02 +08:00
多踩几次坑就好了
zhujinliang
2018-11-07 14:21:32 +08:00
@goofool 通常情况下接收方都是作为消费者,只需读取数据,不需修改数据

如果函数不返回数组切片,就不要修改其内容

如果调用函数是为了获得一个数组的返回,那让函数自行 make,然后返回数组:
func getSlice() []int {
s := make([]int, ...) // 在这个函数内部创建
///
return s
}

outS := getSlice()

如果函数既需要读取数组里的内容,又需要修改这个数组里的数据或追加数据,让函数接收一个数组同时返回一个数组
func modifySlice(s []int) []int {
s = append(s, ...)
return s
}

outS = modifySlice(outS)
goofool
2018-11-07 14:22:57 +08:00
@brucewuio 截取也是一个坑,截取后整个底层数组都释放不了了
goofool
2018-11-07 14:30:48 +08:00
@zhujinliang 这三个方法不错,
第三种情况有些疑问,如何保证 Outs 修改不会影响 s,或者 Outs 修改一定会影响 s,
还是说直接弃用 s,后面的操作都对 Outs 进行
madiks
2018-11-07 14:33:38 +08:00
slice 本身是一个结构体,里面有三个字段:当前 slice 第一个元素在底层数组的指针、slice 长度和 slice 容量。创建 slice 就是基于底层数组生成一个这样的结构体,append 的扩容就是新申请原底层数组一倍的内存,再把原底层数组的内容拷贝过来。大部分时候你不需要关心是否扩容,只要记住 slice 是指类型,作为参数传递会拷贝就行了
```golang
type slice struct {
array unsafe.Pointer
len int
cap int
}
```
推荐阅读: https://research.swtch.com/godata
goofool
2018-11-07 15:03:59 +08:00
lrz0lrz
2018-11-07 16:33:39 +08:00
@dongisking #1 这个坑好像 JS 的
brucewuio
2018-11-07 17:00:00 +08:00
@goofool 就当 cap 多些咯-_-|| 免得 append 又扩容
goofool
2018-11-07 17:31:15 +08:00
@brucewuio append 的时候又把底层数组覆盖了,哈哈😄
asAnotherJack
2018-11-07 17:39:48 +08:00
好巧,几十分钟前也刚看到这儿,看 reader 的 read 方法时想到的这个问题,马一下等 v 友的解答
tiedan
2018-11-07 19:31:11 +08:00
@dongisking 对切片进行切片操作产生的是新的切片,不会影响原来的切片
trait
2018-11-07 19:35:38 +08:00
如果这么容易引起无意操作,没有人提 issue 要求官方给个解决方案么
goofool
2018-11-07 19:58:50 +08:00
@tiedan 这个问题是因为 golang 参数都是值传递吧
dongisking
2018-11-07 20:25:11 +08:00
@tiedan 原来是这样

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/505352

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX