V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
goofool
V2EX  ›  Go 编程语言

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

  •  
  •   goofool · 2018-11-07 13:32:06 +08:00 · 3817 次点击
    这是一个创建于 1994 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    21 条回复    2018-11-12 12:45:11 +08:00
    dongisking
        1
    dongisking  
       2018-11-07 13:37:28 +08:00
    另外一个坑
    cheshire
        2
    cheshire  
       2018-11-07 13:37:30 +08:00 via Android
    初始化的时候能知道大小最好,不然的话指定一个比较大的 capacity
    goofool
        3
    goofool  
    OP
       2018-11-07 13:47:44 +08:00
    @dongisking 这个结果是唯一的吧,会有第二种情况吗
    goofool
        4
    goofool  
    OP
       2018-11-07 13:49:22 +08:00
    @cheshire 如果 slice 作为参数接收到的咋办呢
    brucewuio
        5
    brucewuio  
       2018-11-07 14:10:36 +08:00
    其实《 The Go Programming Language 》 说的挺清楚的 上面也说尽量用数组的抽象 slice 很少直接用数组 加操作直接 append 减操作就[x:y] 截取
    anonymous256
        6
    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
        7
    sirgod  
       2018-11-07 14:21:02 +08:00
    多踩几次坑就好了
    zhujinliang
        8
    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
        9
    goofool  
    OP
       2018-11-07 14:22:57 +08:00
    @brucewuio 截取也是一个坑,截取后整个底层数组都释放不了了
    goofool
        10
    goofool  
    OP
       2018-11-07 14:30:48 +08:00
    @zhujinliang 这三个方法不错,
    第三种情况有些疑问,如何保证 Outs 修改不会影响 s,或者 Outs 修改一定会影响 s,
    还是说直接弃用 s,后面的操作都对 Outs 进行
    madiks
        11
    madiks  
       2018-11-07 14:33:38 +08:00   ❤️ 1
    slice 本身是一个结构体,里面有三个字段:当前 slice 第一个元素在底层数组的指针、slice 长度和 slice 容量。创建 slice 就是基于底层数组生成一个这样的结构体,append 的扩容就是新申请原底层数组一倍的内存,再把原底层数组的内容拷贝过来。大部分时候你不需要关心是否扩容,只要记住 slice 是指类型,作为参数传递会拷贝就行了
    ```golang
    type slice struct {
    array unsafe.Pointer
    len int
    cap int
    }
    ```
    推荐阅读: https://research.swtch.com/godata
    goofool
        12
    goofool  
    OP
       2018-11-07 15:03:59 +08:00
    lrz0lrz
        13
    lrz0lrz  
       2018-11-07 16:33:39 +08:00
    @dongisking #1 这个坑好像 JS 的
    brucewuio
        14
    brucewuio  
       2018-11-07 17:00:00 +08:00
    @goofool 就当 cap 多些咯-_-|| 免得 append 又扩容
    goofool
        15
    goofool  
    OP
       2018-11-07 17:31:15 +08:00 via Android
    @brucewuio append 的时候又把底层数组覆盖了,哈哈😄
    asAnotherJack
        16
    asAnotherJack  
       2018-11-07 17:39:48 +08:00
    好巧,几十分钟前也刚看到这儿,看 reader 的 read 方法时想到的这个问题,马一下等 v 友的解答
    tiedan
        17
    tiedan  
       2018-11-07 19:31:11 +08:00
    @dongisking 对切片进行切片操作产生的是新的切片,不会影响原来的切片
    trait
        18
    trait  
       2018-11-07 19:35:38 +08:00
    如果这么容易引起无意操作,没有人提 issue 要求官方给个解决方案么
    goofool
        19
    goofool  
    OP
       2018-11-07 19:58:50 +08:00
    @tiedan 这个问题是因为 golang 参数都是值传递吧
    dongisking
        20
    dongisking  
       2018-11-07 20:25:11 +08:00
    @tiedan 原来是这样
    reus
        21
    reus  
       2018-11-12 12:45:11 +08:00
    一个 slice 就是一个 slice,不要把它理解成多个 slice+同一个 array
    需要多个 slice,就用 copy
    你就不用理会什么扩容不扩容的事情了,也不会觉得有什么坑了

    @trait 是他们自己没学好而已
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3081 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:53 · PVG 22:53 · LAX 07:53 · JFK 10:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.