英文:
Set value of interface representing nil pointer using reflect in Go
问题
我的问题类似于https://stackoverflow.com/questions/45061568/how-to-initialize-struct-pointer-via-reflection。
我有一个表示空指针的接口。我想要更新空指针背后的值。
我从上述问题的答案中的一个示例中获取了代码,但我的情况稍有不同,给定的解决方案不起作用。
在InitNilPointer()
函数中,值实际上变为&Foo{}
。但是在调用处的结果仍然是(*Foo)(nil)
。我如何使用反射来将foo
在main()
函数中更新为&Foo{}
?
情况如下:
func main() {
var foo *Foo
InitNilPointer(foo)
// Want: &main.Foo{A:""}
fmt.Printf("Want: %+#v\n", &Foo{})
// Got: (*main.Foo)(nil)
fmt.Printf("Got: %+#v\n", foo)
}
// InitNilPointer将给定的指针初始化为nil值,然后变为指向某个值的指针。例如,(*Foo)(nil)变为&Foo{}。
func InitNilPointer(source interface{}) {
v := reflect.ValueOf(source)
if reflect.Indirect(v).IsValid() {
return
}
rv := reflect.ValueOf(&source).Elem()
t := rv.Elem().Type().Elem()
// 这只在本地更新了值。调用处仍然有一个nil指针。遗憾。
rv.Set(reflect.New(t))
// source: &main.Foo{A:""}
fmt.Printf("source: %+#v\n", source)
}
英文:
My question is similar to https://stackoverflow.com/questions/45061568/how-to-initialize-struct-pointer-via-reflection.
I have an interface that represents a nil pointer. I want to update the value behind the nil pointer.
I took the code from one of the examples in the answers to the question mentioned above, but my situation is slightly different, and the given solution isn't working.
Inside InitNilPointer()
the value actually does become &Foo{}
. But the result at the call site remains (*Foo)(nil)
. How can I use reflect to update foo
in main()
to &Foo{}
?
The situation is the following
func main() {
var foo *Foo
InitNilPointer(foo)
// Want: &main.Foo{A:""}
fmt.Printf("Want: %+#v\n", &Foo{})
// Got: (*main.Foo)(nil)
fmt.Printf("Got: %+#v\n", foo)
}
// InitNilPointer initiates the given pointer to a nil value to become a pointer to
// a value. E.g. (*Foo)(nil) becomes &Foo{}.
func InitNilPointer(source interface{}) {
v := reflect.ValueOf(source)
if reflect.Indirect(v).IsValid() {
return
}
rv := reflect.ValueOf(&source).Elem()
t := rv.Elem().Type().Elem()
// This only updates the value locally. The call site still has a nil pointer. SAD.
rv.Set(reflect.New(t))
// source: &main.Foo{A:""}
fmt.Printf("source: %+#v\n", source)
}
答案1
得分: 2
无论你将什么传递给函数,都会创建一个副本。如果你传递的是 foo
,无论函数做什么,它只能修改副本,而不能修改原始的 foo
变量。
所以你必须传递 &foo
(并且修改所指向的对象将修改 foo
):
func main() {
var foo *Foo
InitNilPointer(&foo)
fmt.Printf("Want: %+#v\n", &Foo{})
fmt.Printf("Got: %+#v\n", foo)
}
func InitNilPointer(source interface{}) {
rv := reflect.ValueOf(source).Elem()
if reflect.Indirect(rv).IsValid() {
return
}
t := rv.Type().Elem()
rv.Set(reflect.New(t))
// source: &main.Foo{A:""}
fmt.Printf("source: %+#v\n", source)
}
这将输出(在 Go Playground 上尝试):
source: (*main.Foo)(0xc00000e028)
Want: &main.Foo{A:""}
Got: &main.Foo{A:""}
英文:
Whatever you pass to a function, a copy is made. If you pass foo
, no matter what the function does, it can only modify the copy but not the original foo
variable.
So you must pass &foo
(and modifying the pointed object will modify foo
):
func main() {
var foo *Foo
InitNilPointer(&foo)
fmt.Printf("Want: %+#v\n", &Foo{})
fmt.Printf("Got: %+#v\n", foo)
}
func InitNilPointer(source interface{}) {
rv := reflect.ValueOf(source).Elem()
if reflect.Indirect(rv).IsValid() {
return
}
t := rv.Type().Elem()
rv.Set(reflect.New(t))
// source: &main.Foo{A:""}
fmt.Printf("source: %+#v\n", source)
}
This will output (try it on the Go Playground):
source: (**main.Foo)(0xc00000e028)
Want: &main.Foo{A:""}
Got: &main.Foo{A:""}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论