英文:
How do you set a value to a pointer containing nil using reflection
问题
你在尝试将一个值设置给一个结构体中的空指针,代码如下:
// https://play.golang.org/p/jPTMNC_ZQ9
package main
import (
"fmt"
"reflect"
)
type T struct {
A *int
}
func main() {
fmt.Println("Hello, playground")
t := &T{}
v := 1
vptr := &v
CopyValue(vptr, t.A) // 我想将t.A设置为1
}
func CopyValue(src interface{}, dest interface{}) {
srcRef := reflect.ValueOf(src)
if srcRef.Kind() == reflect.Ptr {
srcRef = srcRef.Elem()
}
destRef := reflect.New(srcRef.Type()).Elem()
destRef.Set(srcRef)
reflect.ValueOf(dest).Elem().Set(destRef)
}
然而,你遇到了以下错误:
panic: reflect: call of reflect.Value.Set on zero Value
goroutine 1 [running]:
reflect.flag.mustBeAssignable(0x0, 0x1040a128)
/usr/local/go/src/reflect/value.go:221 +0x260
reflect.Value.Set(0x0, 0x0, 0x0, 0xdefc0, 0x1040a128, 0x182)
/usr/local/go/src/reflect/value.go:1339 +0x40
main.CopyValue(0xd7860, 0x1040a124, 0xd7860, 0x0)
/tmp/sandbox487854080/main.go:30 +0x1a0
main.main()
/tmp/sandbox487854080/main.go:19 +0x100
我做错了什么?
英文:
I'm trying to set a value to a nil pointer in a struct like so.
// https://play.golang.org/p/jPTMNC_ZQ9
package main
import (
"fmt"
"reflect"
)
type T struct {
A *int
}
func main() {
fmt.Println("Hello, playground")
t := &T{}
v := 1
vptr := &v
CopyValue(vptr, t.A) // I want to set t.A to contain 1
}
func CopyValue(src interface{}, dest interface{}) {
srcRef := reflect.ValueOf(src)
if srcRef.Kind() == reflect.Ptr {
srcRef = srcRef.Elem()
}
destRef := reflect.New(srcRef.Type()).Elem()
destRef.Set(srcRef)
reflect.ValueOf(dest).Elem().Set(destRef)
}
However, I encounter the following error:
panic: reflect: call of reflect.Value.Set on zero Value
goroutine 1 [running]:
reflect.flag.mustBeAssignable(0x0, 0x1040a128)
/usr/local/go/src/reflect/value.go:221 +0x260
reflect.Value.Set(0x0, 0x0, 0x0, 0xdefc0, 0x1040a128, 0x182)
/usr/local/go/src/reflect/value.go:1339 +0x40
main.CopyValue(0xd7860, 0x1040a124, 0xd7860, 0x0)
/tmp/sandbox487854080/main.go:30 +0x1a0
main.main()
/tmp/sandbox487854080/main.go:19 +0x100
What am I doing wrong?
答案1
得分: 5
为了能够修改t.A
指向的内容,你需要将其引用传递给CopyValue
函数。
CopyValue(vptr, &t.A) //(注意 & 符号)
然后,你可以将指针赋值给新的地址:
func CopyValue(src interface{}, dest interface{}) {
srcRef := reflect.ValueOf(src)
vp := reflect.ValueOf(dest)
vp.Elem().Set(srcRef)
}
参考这里的第三个“反射定律”:https://blog.golang.org/laws-of-reflection
完整的工作代码:
package main
import (
"fmt"
"reflect"
)
type T struct {
A *int
}
func main() {
t := &T{}
v := 1
vptr := &v
CopyValue(vptr, &t.A) // 我们传递了对 t.A 的引用,因为我们想要修改它
fmt.Printf("%v\n", *t.A)
}
func CopyValue(src interface{}, dest interface{}) {
srcRef := reflect.ValueOf(src)
vp := reflect.ValueOf(dest)
vp.Elem().Set(srcRef)
}
英文:
In order to be able to modify what t.A
points to, you need to send a reference to it to your CopyValue
function.
CopyValue(vptr, &t.A) // (note the &)
You can then assign the pointer to the new address:
func CopyValue(src interface{}, dest interface{}) {
srcRef := reflect.ValueOf(src)
vp := reflect.ValueOf(dest)
vp.Elem().Set(srcRef)
}
See the 3rd "law of reflection" here: https://blog.golang.org/laws-of-reflection
Full working code:
package main
import (
"fmt"
"reflect"
)
type T struct {
A *int
}
func main() {
t := &T{}
v := 1
vptr := &v
CopyValue(vptr, &t.A) // we pass a reference to t.A since we want to modify it
fmt.Printf("%v\n", *t.A)
}
func CopyValue(src interface{}, dest interface{}) {
srcRef := reflect.ValueOf(src)
vp := reflect.ValueOf(dest)
vp.Elem().Set(srcRef)
}
答案2
得分: 1
reflect.ValueOf(dest).Elem().Set(destRef)
这一行代码中,reflect.ValueOf(dest)
会返回nil,因为你传入了一个nil指针。在这个nil指针上调用.Elem()
是无效的,因为nil指针没有元素。
英文:
reflect.ValueOf(dest).Elem().Set(destRef)
If you look into this line, reflect.ValueOf(dest)
will give you nil, since you passed in a nil pointer. Calling .Elem()
on this is invalid, since there is no element to the nil pointer.
答案3
得分: 1
t.A
在传入时是一个空指针,所以CopyValue
被要求将一个值复制到一个无效(空)的位置。你需要为它分配一个int类型的空间,然后CopyValue
就能够将值复制到指向的位置。
以下代码解决了这个错误并允许值被复制:
t := &T{}
t.A = new(int) // 添加这一行
英文:
t.A
is a nil pointer when you pass it in, so CopyValue
is being asked to copy a value into an invalid (nil) location. You need to allocate space for an int for it to point to, and then CopyValue
will be able to do the copy into the location pointed at.
This resolves the error and allows the value to be copied:
t := &T{}
t.A = new(int) // Add this line
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论