我想创建元素,将其添加到切片中并通过其地址进行更改。我希望元素从外部的变化也会改变一个切片。但是添加后,将创建一个新切片。我使用序列化,所以使用地址切片是不合适的,元素的添加也发生在不同的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]
,则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
和a
是不同的变量;或者更准确地说,变量b
和a
的后备数组为其元素保留内存(包括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
是一个这样的位置,切片内的元素是另一个。
您很可能需要存储指针而不是int
s。
现在关于序列化 - 我不确定您有什么样的想法,但总的来说,您可以像下面这样进行:
type myArray []*int
var a myArray
//...
func (x myArray) Serialize() []byte { .... }
Serialize
满足序列化程序使用的接口的位置。