如何使用反射将值设置为包含nil的指针

时间:2017-07-16 23:14:21

标签: go reflection

我正在尝试在结构中将值设置为nil指针。

// 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)
}

但是,我遇到以下错误:

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

我做错了什么?

3 个答案:

答案 0 :(得分:3)

为了能够修改t.A指向的内容,您需要向CopyValue函数发送对它的引用。

CopyValue(vptr, &t.A) // (note the &)

然后,您可以将指针指定给新地址:

func CopyValue(src interface{}, dest interface{}) {
    srcRef := reflect.ValueOf(src)
    vp := reflect.ValueOf(dest)
    vp.Elem().Set(srcRef)
}

参见第3"反思定律"在这里: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) // 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)
}

答案 1 :(得分:1)

<!DOCTYPE html> <html> <body> <h2>Picture of Shiva</h2> <img src=”https://s3.us-east-2.amazonaws.com/newtestshivcloudtech/shiva.jpg” /> </body> </html>

如果你查看这一行,reflect.ValueOf(dest).Elem().Set(destRef)将给你nil,因为你传入了一个nil指针。在此调用reflect.ValueOf(dest)无效,因为nil指针没有元素。

答案 2 :(得分:1)

传递它时,

t.A是一个nil指针,因此要求CopyValue将值复制到无效(零)位置。您需要为int指定空间以指向它,然后CopyValue将能够复制到指向的位置。

这可以解决错误并允许复制值:

t := &T{}
t.A = new(int) // Add this line