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

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?

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
", *t.A)
}

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

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.

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