2017-05-02 15 views
0

Goのリフレクションパッケージを使用すると、ポインタがnilの場合に構造体にポインタを設定する方法はありますか?反射パッケージを見ると、reflect.Value.CanSet()falseの場合、Set()の呼び出しはパニックになります。これを回避する別の方法は、構造体への直接参照に依存せず、リフレクトパッケージを使用するだけですか?たとえば、以下のコードで空の姓を "Johnson"に設定するにはどうすればよいですか?あなたはLastNameフィールドに値を設定する必要があるためGolangは、構造体にnil文字列ポインタ値を設定します。

package main 

import (
    "fmt" 
    "reflect" 
) 

type Person struct { 
    FirstName *string 
    LastName *string 
} 

func main() { 
    p := Person{} 
    firstName := "Ryan" 
    p.FirstName = &firstName 

    rp := reflect.ValueOf(p) 
    fmt.Println("rp:", rp) 

    for i := 0; i < rp.NumField(); i++ { 
     fmt.Printf("%s: Pointer: %d CanSet: %t\n", rp.Type().Field(i).Name, rp.Field(i).Pointer(), rp.Field(i).Elem().CanSet()) 
    } 

    rp.Field(0).Elem().SetString("Brian") 
    fmt.Println(*p.FirstName) 

    // Yields nil pointer error 
    // rp.Field(1).Elem().SetString("Johnson") 
    // fmt.Println(*p.LastName) 

    fmt.Println(rp.Field(1).Type()) 
    fmt.Println(rp.Field(1).CanSet()) 
    // fmt.Println(rp.Field(1).Elem().Type()) // nil pointer here also 
    fmt.Println(rp.Field(1).Elem().CanSet()) 
} 

See in Golang Playground

+0

p := &Person{} 

次に、あなたが文字列値を設定することができますLastNameフィールドに有効なポインタ値を設定することができます。 ..なぜあなたはこれをしたいですか?私は自分自身が文字列へのポインタを使用する理由の多くを見たことがなく、標準ライブラリで使用されているのを見たこともありません。 – RayfenWindspear

+1

公正な質問。 REST APIを公開すると、クライアントがフィールドを提供したかどうかを知ることができます。それらがポインタでない場合、文字列の空の値は '' ''です。それから、私はクライアントに '' ''を提供したのか、それとも何も提供しなかったのかを尋ねなければならないでしょうか?さらに、 'Validate'や' Transform'のような構造体フィールドに一意のタグを追加しています。だから、私はそれらを解析するために反射パッケージを使用しています。 –

答えて

5

あなたはまず、Person{}へのポインタを必要とします。私はここに明白な質問をします

rp.Field(1).Set(reflect.New(rp.Field(1).Type().Elem())) 
rp.Field(1).Elem().SetString("Jones") 

https://play.golang.org/p/f5MjpkDI2H

関連する問題