Go 是否可以更改存储在空接口中的结构的成员
我有这个:Go 是否可以更改存储在空接口中的结构的成员,go,Go,我有这个: type pair struct { a, b int } 然后我定义了两个变量: x := pair{ 3, 4 } var y interface{} = x 我意识到y不存储x的引用,而是通过以下代码存储其副本: x.b = 7 fmt.Println(x) fmt.Println(y) // got: // {3 7} // {3 4} 另见: 是否有任何方法可以修改y中复制的结构的pair.y成员 尝试此:(失败) 尝试此:(也失败) 将“b”更改为“b”:(
type pair struct {
a, b int
}
然后我定义了两个变量:
x := pair{ 3, 4 }
var y interface{} = x
我意识到y
不存储x
的引用,而是通过以下代码存储其副本:
x.b = 7
fmt.Println(x)
fmt.Println(y)
// got:
// {3 7}
// {3 4}
另见:
是否有任何方法可以修改y中复制的结构的pair.y
成员
尝试此:(失败)
尝试此:(也失败)
将“b”更改为“b”:(也失败)
更新: 我不打算用y来更改
x.b
。我想单独更改y
的字段b
感谢您的帮助,但这不是一个关于值和引用的简单问题。您需要首先了解指针和地址。使用指针可以深入更改值。如果您希望y与x具有相同的值,它们需要指向相同的地址。我找到了一个解决方案:
package main
import (
"unsafe"
"fmt"
)
type pair struct {
a, b int
}
func main() {
x := pair{ 3, 4 }
var y interface{} = x
var z interface{} = y
// change x.b
x.b = 7
// change y.b
addr := (*(*[2]uintptr)(unsafe.Pointer(&y)))[1]
pp := (*pair)(unsafe.Pointer(addr))
pp.b = 8
fmt.Println(x) // {3 7}
fmt.Println(y) // {3 8}
fmt.Println(z) // {3 8}
}
这真是一个骇客
有人能提供一个更自然/更习惯的吗
总结:
- 将具体值指定给空接口会复制该值
- 将空接口分配给另一个空接口会导致它们共享相同的基础值
x.b
,我想更改y
中存储的复制结构的成员@brk x根本没有对y的引用。如果您的作用域中只有x,并且希望修改y的一个成员,而该成员不在您的作用域中,您将无法修改,反之亦然,y没有对x的引用等@dlamblin,但y有一个指向复制的结构的引用/指针。现在,自您的更新以来,它变得更清晰了,它可能是:@mgagnon的副本。我不这么认为。我的问题是,当您将结构值分配给空接口(该结构值被复制,并且与原始接口没有关系)时,实际会发生什么,以及如何访问复制的值。我发现这很微妙,很容易被误解。好吧,可能不是完全的复制品,但它展示了如何使用反射来做你想做的事情。你需要思考y
,(通过使用&y
)@mgagnon为什么使用y的地址可以让我在值中设置一个字段?因为Go中的所有内容都是通过值传递的,所以如果reflect.ValueOf()
在y
的副本上工作,它不会修改原始的y
变量。没有自然,这是一种惯用的方法,因为这不是应该做的。go中的所有作业都是副本,因此,事实上,这甚至与共享相同值的y
和z
一样有效,这是一个实现细节。@JimB我同意你的看法。也许我的问题应该重新命名为“在golang中,是否应该将空接口持有的值视为不可变/只读”。但是有没有描述这种行为的规范?如果你同意,那么我不理解这个问题。Go接口是指定的,并且与任何其他值一样进行操作。它是“不可变的”,就像一个字符串是不可变的一样,就像一个字符串一样,你可以通过使用一些不安全的方法来规避这种不可变性。是的,你可以绕过或打破任何你想要的不安全的东西,但这并不意味着它需要,@ Jimb,我认为它们是类似变量的,可以存储任何大小的对象,而不是C++中的代码> const char */c>,它指向常量内存。这里的不安全操作表明,你似乎理解实现,这相当简单,所以我不确定这是怎么一回事。接口当前实现为一个不透明的2字值(不考虑方法集)——一个字表示动态类型,一个字表示指向动态值的指针。你为什么要用这种语言来访问一些未指定的行为,而这些行为你首先可以使用指针?
// panic: reflect: reflect.Value.SetInt using value obtained using unexported field
v := reflect.ValueOf(y).FieldByName("b")
v.SetInt(33)
type pair {
a, B int
}
// panic: reflect: reflect.Value.SetInt using unaddressable value
v := reflect.ValueOf(y).FieldByName("B")
v.SetInt(33)
package main
import (
"unsafe"
"fmt"
)
type pair struct {
a, b int
}
func main() {
x := pair{ 3, 4 }
var y interface{} = x
var z interface{} = y
// change x.b
x.b = 7
// change y.b
addr := (*(*[2]uintptr)(unsafe.Pointer(&y)))[1]
pp := (*pair)(unsafe.Pointer(addr))
pp.b = 8
fmt.Println(x) // {3 7}
fmt.Println(y) // {3 8}
fmt.Println(z) // {3 8}
}