是使用引用还是复制指向切片的指针?

我发现我的代码有不同的结果,如下所示,这是一个指向 Go.Tour 编译器(http://tour.golang.org/welcome/1)和我的本地编译器(Go 版本 1.4)之间的幻灯片的指针


哪一个是正确的?而且我还想知道我的代码 p1、p2 之间的指针是如何工作的?因为地址似乎没有移动,但 p1 使用引用,而 p2 使用复制。


package main


import "fmt"


func main() {

    var a []int

    var b []int

    a = append(a, 0)

    b = append(b, 0)

    p := &a[0]

    fmt.Printf("a[0] = %d pointer=%d, p = %d \n", a[0], &a[0], *p)

    a[0] = 2

    fmt.Printf("a[0] = %d pointer=%d, p = %d \n", a[0], &a[0], *p)

    /*

        a[0] = 0, p = 0

        a[0] = 2, p = 2

    */

    var c []int

    var d []int

    c = append(c, 0)

    d = append(d, 0)

    p2 := &c[0]

    fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)

    c = append(c, 1)

    c[0] = 2

    fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)

    /* 

        c[0]=0, p2 = 0

        c[0]=2, p2 = 0


      copy the same code run in http://tour.golang.org/welcome/1 will get.

        c[0]=0, p2 = 0

        c[0]=2, p2 = *2*  << why??


    */

}

更新:我使用指向切片的指针的原因是我试图测试在 Go 的 Web 端存在 RUST 的向量 push_pack 问题。请参阅http://doc.rust-lang.org/nightly/intro.html#ownership。


海绵宝宝撒
浏览 124回答 2
2回答

RISEBY

首先,对于任何带有切片的内容,我建议您阅读Go Slices: usage and internals。简短的故事是 Go 使用 append 处理切片的容量可能很不稳定。给定的切片变量具有三个组成部分:指向数据数组的底层指针、长度和容量。已经有很多关于差异的说法,但这里的重要部分是长度是(有效)当前使用的底层内存缓冲区的部分,容量是底层缓冲区的整体大小。这是一个不精确的定义,但它在实践中效果很好。神秘的下一部分是append内置函数。append 的功能有时实际上有点难以推理,这可能是 Go 中最大的问题之一:如果底层缓冲区足够大(cap > len),只需将 len 增加要添加的元素数并将数据放入新空间。如果底层缓冲区不够大,则分配一个更大容量的新缓冲区,将旧缓冲区复制到新缓冲区中,然后添加所有新元素。2 的最大症结在于,在追加之后对同一个切片进行两次任意操作,很难知道旧的或新的内存缓冲区是否被先验地影响。确实,让我们试试这个:var c []intvar d []intc = append(c, 0)d = append(d, 0)p2 := &c[0]fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)c = append(c, 1)c[0] = 2fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)c = append(c, 1)c[0] = 25fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)你会得到c[0]=25, p2=2。我们只添加了一个语句,突然间指针和切片值发散了!这意味着上限发生了变化,或者更确切地说,使用了新的缓冲区。实际上,cap(c)在第一个 append 之后但在第三个之前打印,将产生2. 这意味着当将单个元素附加到容量为 0 的切片时,Go 会初始化 [footnote] 长度为 1 和容量为2的切片。所以在第二次追加之后没有分配新的缓冲区,因为有空间。这就是为什么p2和c[0]在第二次追加之后是一样的,但在第三次之后是一样的。一般来说,虽然切片和对内存中特定位置的引用的确切规则是一致的,但在实践中切片增长的行为非常挑剔,通常最好永远不要依赖指向切片值(或两个切片变量)的指针具有相同的底层缓冲区),除非您计划从不使用 append,或者将缓冲区预先分配make到使用 append 永远不会重新分配的大小。[脚注] 不完全正确,我想给出一个巨大的警告,即 append 后的确切容量取决于实现。请不要依赖 APPEND 导致编译器之间或什至不同编译器目标之间一致的容量
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go