代码之家  ›  专栏  ›  技术社区  ›  Сергей Ефремов

附加到片的元素的地址

  •  2
  • Сергей Ефремов  · 技术社区  · 7 年前

    我想创建元素,将其添加到切片中,并根据其地址对其进行更改。我希望外部元素的变化也会改变一个片段。但是在添加之后,会创建一个新的切片。我使用序列化,因此使用地址片是不合适的,而且元素的添加发生在不同的goroutine中,因此访问最后添加的元素也是不合适的。

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        var a []int
        b := 1
        fmt.Println("old addr:", &b)
        // old addr: 0x10414020
        a = append(a, b)
        fmt.Println("new addr:", &a[0])
        // new addr: 0x10414028
    }
    

    play golang example

    3 回复  |  直到 7 年前
        1
  •  4
  •   icza    7 年前

    这不是一个 append() 创建新的切片标头和备份数组。

    这是您附加的问题 b 到切片 a ,的值的副本 b 将追加变量。您附加了 价值 ,不是 变量 哦!顺便说一句,追加(或赋值)会复制要追加(或赋值)的值。

    请注意 b a[0] 如果你不打电话也会不一样 附加() 而是预先分配切片并简单地分配 b a【0】 :

    var a = make([]int, 1)
    b := 1
    fmt.Println("old addr:", &b)
    // old addr: 0x10414024
    a[0] = b
    fmt.Println("new addr:", &a[0])
    // new addr: 0x10414020
    

    试穿一下 Go Playground

    这是因为变量 b 是不同的变量;或者更准确地说是变量 b 的后备数组为其元素保留内存(包括 a【0】 ),因此它们的地址不能相同!

    不能创建放置在另一个变量相同内存位置的变量。为了达到这个“效果”,你手头有指针。您必须创建一个指针变量,可以将其设置为指向另一个现有变量。通过访问和修改 指出 值,有效地访问和修改存储在指针中的变量的地址。

    如果您想在 可以访问和修改“局外人”的切片 b 变量,最简单的方法是存储其地址,其类型为 *int

    示例:

    var a []*int
    b := 1
    fmt.Println("b's addr:", &b)
    a = append(a, &b)
    fmt.Println("addr in a[0]:", a[0])
    
    // Modify b via a[0]:
    *a[0] = *a[0] + 1
    fmt.Println("b:", b)
    

    输出(在 Go Playground ):

    b's addr: 0x10414020
    addr in a[0]: 0x10414020
    b: 2
    
        2
  •  0
  •   mbuechmann    7 年前

    赋值总是让运行时为复制的值分配新内存,并且分配的内存将有另一个地址。如果附加到一个值片,则始终会复制变量。

    如果必须从不同的go例程访问元素,则必须使其线程安全。无论是使用值还是引用,都必须这样做。

        3
  •  0
  •   Wojciech Kaczmarek    7 年前

    引用的程序行为完全正确-地址表示存储位置, b int 是这样一个位置,而切片中的元素是另一个。

    您很可能需要存储指针,而不是 int s

    现在,关于序列化,我不确定您的想法是什么,但一般来说,您可以按照以下方式进行:

    type myArray []*int
    var a myArray
    //...
    
    func (x myArray) Serialize() []byte { .... }
    

    哪里 Serialize 满足序列化程序使用的接口。