我想创建元素,将其添加到切片并按地址更改。我希望元素从外部的变化也会改变。但在添加之后,会创建一个新切片。我使用序列化,因此使用一片地址是不合适的,也会在不同的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
}
答案 0 :(得分:3)
这不是append()
创建新切片标头和支持数组的问题。
这是您将b
附加到切片a
的问题,将追加b
变量值的副本。您附加值,而不是变量!顺便说一句,追加(或分配)会附加(或分配)值的副本。
请注意,如果您不致电b
,而是预先分配切片,只需将a[0]
分配给{{1},append()
和b
的地址也会有所不同}}:
a[0]
在Go Playground上尝试。
这是因为变量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
和b
是不同的变量;或者更准确地说,变量a
和b
的后备数组为其元素保留了内存(包括a
的内存空间),因此它们的地址不能相同!
您无法创建放置到另一个变量的同一内存位置的变量。为了达到这个“效果”,你手头有指针。您必须创建一个指针变量,您可以将其设置为指向另一个现有变量。通过访问和修改指向值,您可以有效地访问和修改存储在指针中的地址的变量。
如果你想在a[0]
切片中存储“东西”,通过它可以访问和修改“局外人”a
变量,最简单的方法是存储其地址,这将是类型b
。
示例:
*int
输出(在Go Playground上尝试):
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)
答案 1 :(得分:0)
引用程序行为完全正确 - 地址表示存储位置,b int
是一个这样的位置,切片内的元素是另一个。
你很可能需要存储指针而不是int
s。
现在关于序列化 - 我不确定你有什么样的想法,但总的来说你可以像下面这样进行:
type myArray []*int
var a myArray
//...
func (x myArray) Serialize() []byte { .... }
Serialize
满足您的序列化器使用的接口。
答案 2 :(得分:0)
分配值始终允许运行时为复制的值分配新内存,并且分配的内存将具有另一个地址。如果附加到一片值,则始终复制变量。
如果必须访问来自不同go例程的元素,则必须使其成为线程安全的。无论您使用的是值还是引用,都必须这样做。