追加到切片的元素的地址



我想创建元素,将其添加到切片中并通过其地址进行更改。我希望元素从外部的变化也会改变一个切片。但是添加后,将创建一个新切片。我使用序列化,所以使用地址切片是不合适的,元素的添加也发生在不同的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
}

玩戈朗示例

这不是append()创建新的切片标头和支持数组的问题。

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

请注意,如果您不调用append()而是预分配切片并简单地将b分配给a[0],则ba[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上尝试一下。

这样做的原因是变量ba是不同的变量;或者更准确地说,变量ba的后备数组为其元素保留内存(包括a[0]的内存空间),所以它们的地址不能相同!

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

如果要将"某些内容"存储在a切片中,通过该切片可以访问和修改"局外人"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

分配值始终允许运行时为复制的值分配新内存,并且分配的内存将具有另一个地址。如果追加到值切片,则始终复制变量。

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

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

您很可能需要存储指针而不是ints。

现在关于序列化 - 我不确定您有什么样的想法,但总的来说,您可以像下面这样进行:

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

Serialize满足序列化程序使用的接口的位置。