2013-05-06

Go の struct に任意の名前のフィールドがあるか調べる

静的型付け言語たる Go ですが、実行時にごにょごにょすることを reflection と言うらしく、reflect パッケージが標準で入っています。

v := Foo{}
structField, found := reflect.TypeOf(v).FieldByName("x")

Foo 型に x フィールドが存在すれば、found に true が入ります。http://play.golang.org/p/F9TY4RcBEC

値とポインタは異なった型なので、もとの struct にたどり着くまでの道筋が異なります。 http://play.golang.org/p/_V19gURisU

v := Foo{}
typeFromValue := reflect.TypeOf(v) 

p := new(Foo)
typeFromPointer := reflect.TypeOf(p).Elem()

それから struct 定義のとき、各フィールドにタグをつけられますが、これも reflect パッケージを使って取得できます。http://play.golang.org/p/K__zcCZ7Nd

type Foo struct {
 int
 x string `wozozo:"show" hoge:"fuga"`
}

func main() {
 v := Foo{}
 t := reflect.TypeOf(v)
 field, _ := t.FieldByName("x")
 fmt.Println(field.Tag)  // => `wozozo:"show" hoge:"fuga"`
 fmt.Println(field.Tag.Get("wozozo")) // => show
}

フィールドにつけるタグは文字列ならなんでもいいのですが、key:"value" のフォーマットをスペース区切りにしたものを定義すると、structTag.Get(key) で value を取得できます。Google App Engine では、エンティティのフィールド定義に struct を書くときに、インデックスしてくれるな、とか、struct には含むけどエンティティとして保存するな、のような指示に使われています。