2017-07-16 10 views
2

私は構造体のようにnilポインタに値を設定しようとしています。どのように反映を使用して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 

は私が間違って何をしているのですか?あなたはこのラインに見える場合は、NULLポインタで渡されたので、

+1

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

がここに第三 "反射の法則" を参照してください。それとは別に、 'vptr'を渡して' * vptr'をコピーするのではなく、 'v'を渡してコピーする方が直感的です。あなたが '* vptr'をコピーしたいなら、' vptr'の代わりに '* vptr'を渡してください。ランタイムパニックを回避する例については、https://play.golang.org/p/daDVbMp3emを参照してください。 –

+0

@ChronoKitsuneどのような素晴らしい例! T.Aが指していたアドレスとT.Aを設定する必要があるときに、T.Aが指していた値を設定していると思いました。 –

答えて

3

t.Aポイントには変更できるようにするために、あなたはあなたのCopyValue関数に参照を送信する必要があります。

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

あなたは、新しいアドレスへのポインタを割り当てることができます。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)は、あなたがnilを与えるだろう。これに対して.Elem()の呼び出しは無効です。なぜなら、nilポインタの要素がないからです。

1

t.Aは、それを渡すときにnilポインタです。したがって、CopyValueは無効な(nil)位置に値をコピーするよう要求されています。あなたが指すためにintのためのスペースを割り当てる必要があります。そして、CopyValueは、で指した場所にコピーを行うことができます。

これは、エラーを解決し、値をコピーすることができます:

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

あるいは、 '&t.A'を渡すことができ、' reflect.New'を使うことができます。 https://play.golang.org/p/daDVbMp3em( '* vptr'ではなく' v'をコピーする方が直感的であるため、 'srcRef.Elem()'や 'vptr'は使わなかった) –

関連する問題