[Go言語] reflectパッケージで変数の値を変える

September 21, 2013

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

以下の記事に書いてあることをまとめる。

変数の値を変える

よく考えれば当たり前だが、一度ポインタにしないと変数の値を変えることができない。

http://play.golang.org/p/grX4uYh2VO

package main

import (
	"fmt"
	"reflect"
)

func main() {
	n := 100

	// ダメ
	nv := reflect.ValueOf(n)
	fmt.Println(nv.CanSet())

	// ポインタを使う
	npv := reflect.ValueOf(&n)
	fmt.Println(npv.Elem().CanSet())
	npv.Elem().SetInt(200)

	fmt.Println(n)
}

一度ポインタにして、Elemメソッドでまたポインタの指す先に戻しているあたりが気持ち悪い。 Elemメソッドのソースを見ると、flagROフラグは元のValueの物を保持して、flagAddrフラグとflagIndirフラグを立てている。そのため、CanSetメソッドでtrueが返る(つまり、代入可能にしている)ことが分かる。 一方、reflect.ValueOf(100)のようにした場合は、flagIndirしかフラグがたてられない。よって、CanSetはfalseとなり、Setできない。

構造体のフィールドの値を変える

上記と同様に、構造体のフィールドの値を変えるのにも一度ポインタに変換する必要がある。

http://play.golang.org/p/SSW28W5bXn

package main

import (
	"fmt"
	"reflect"
)

type Hoge struct {
	N int
}

func main() {
	h := Hoge{10}
	hpv := reflect.ValueOf(&h)
	hpv.Elem().FieldByName("N").SetInt(200)

	fmt.Println(h)
}