2017-07-16 88 views
2

我想設置一個值爲一個零結構像這樣的指針。如何設置一個值包含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 

我在做什麼錯?

+1

另外:傳遞和複製'v'可能更直觀,而不是傳遞'vptr'和複製'* vptr';如果你想複製'* vptr',然後傳遞'* vptr'而不是'vptr'。有關避免運行時恐慌的示例,請參閱https://play.golang.org/p/daDVbMp3em。 –

+0

@ChronoKitsune多麼偉大的例子!我以爲我正在設定T.A指向的值,當時我應該設置地址&T.A指向的地址。 –

回答

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

看到這裏第三屆 「反射定律」: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

reflect.ValueOf(dest).Elem().Set(destRef)

如果你看看這條線,reflect.ValueOf(dest)會給你爲零,因爲你在一個零指針傳遞。對此調用.Elem()是無效的,因爲沒有元素指向nil指針。

1

t.A當你傳入它時,它是一個零指針,因此要求CopyValue將一個值複製到一個無效(無)位置。您需要爲它指定的int分配空間,然後CopyValue將能夠複製到指向的位置。

這解決了錯誤,並允許值被複制:

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

或者,'&t.A'可以通過,並且可以使用'reflect.New'。 https://play.golang.org/p/daDVbMp3em(我沒有使用'srcRef.Elem()'或'vptr',因爲我更加直觀地複製'v'而不是'* vptr') –