go语言中的slice一些使用注意事项

平山居士 · · 319 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

golang中的slice很灵活,功能也很强悍,不过对于初学者来说会容易被它坑到,此篇文章就尽量提及到使用slice的一些容易容易出错的地方,以下示例使用的golang版本为1.14.2。

作为参数传递

在go语言中的方法的参数都为值传递,切片也不例外,但是切片有一个指向数据地址的指针,所以就算是值传递,如果改变切片中的已有元素数据,也有可能影响到原有的切片

为什么是可能呢?我们来看下面的代码

func test(a []int) {
    a = append(a, 1)
    a[0] = 2
}

func main() {
    s1 := make([]int, 1, 1)
    log.Printf("%v\n", s1) // [0]
    test(s1)
    log.Printf("%v\n", s1) // [0]
}

这里的s1变量并没有被影响到数据;那么我们再来看下面的代码

func test(a []int) {
    a = append(a, 1)
    a[0] = 2
}

func main() {
    s1 := make([]int, 1, 2)
    log.Printf("%v\n", s1) // [0]
    test(s1)
    log.Printf("%v\n", s1) // [2]
}

咦,这里的s1就已经被改变了,这是为什么呢?我们可以看看append方法的注解,如果目的切片容量足够,那么会直接添加到原切片指向的数据地址再返回一个拥有新长度和原数据地址的新切片,所以直接修改原切片长度内的数据会影响到原切片数据;目的切片容量不足时才会另外申请空间,此时新切片拥有新的数据地址,所以不会影响到原有切片。

注意append总是会返回一个新切片;原切片容量足够时,新切片指向的数据地址不变,依然是原切片指向的数据地址

作为方法返回值

当切片作为方法返回值时也有几点值得注意

只返回了一个切片的一部分时,并不会复制数据,而是直接指向原地址

这样的话如果一直在引用返回的切片时,整个切片都不会被释放,一直在内存中

如果返回的切片是一个很多地方都可以获取到的同一切片变量,比如

var a = []int{1, 2, 1}

func GetA() []int{
    return a
}

那么此时也没有真正做到值传递,外面的修改可能会影响到a,并且如果有多个协程获取并修改的话,还有并发同步问题

我们可以以下面的方式返回一个指向新地址的slice解决上面的问题,做到真正的值传递

func GetA() []int{
    return append([]int{}, a...)
}

nil切片

一个nil切片也是可以使用len()方法的,此时为0,如果不需要判断切片是否为nil则直接使用len()方法即可


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:平山居士

查看原文:go语言中的slice一些使用注意事项

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

319 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传