Go の reflect パッケージ頻出関数めも
TypeOf(interface{}) reflect.Type
引数に与えられた値の型情報を取得する。取得結果は Type というインタフェース型であり、Type を利用して元の型のメソッドや要素情報、パッケージのパスなど、型に関するさまざまな情報を参照することができる。※全ての型で Type のメソッドすべてが利用できるというわけではないので、Type の保有メソッドを利用する前には Kind() 関数で型の種別を調査すること。
type MyStruct struct {
Id string
Code int
}
m := new(MyStruct)
rt := reflect.TypeOf(m)
fmt.Println(rt) // *main.MyStruct
Kind() reflect.Kind
Type が保有しているメソッドの一つ。TypeOf などで取得した Type がどのプリミティブ型に該当するかを再起的に検証する。
type MyStruct struct {
Id string
Code int
}
m := new(MyStruct)
rt := reflect.TypeOf(m)
kind := rt.Kind()
fmt.Println(kind) // ptr
m2 := MyStruct{}
rt2 := reflect.TypeOf(m2)
kind2 := rt2.Kind()
fmt.Println(kind2) // struct
type MyMyStruct MyStruct
m3 := MyMyStruct{}
rt3 := reflect.TypeOf(m3)
kind3 := rt3.Kind()
fmt.Println(kind3) // struct
Kind 関数は Kind 型を返却し、 Kind 型については下記のように uint の値と紐づく定数が設定されている。
ValueOf などで得られる reflect.Value に対しても利用でき、返却値についての挙動は同じ。
type Kind uint
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
(略)
Ptr
Slice
String
Struct
UnsafePointer
)
TypeOf などで取得したモノのプリミティブな型が目的の型と一致するかどうかなどを検証する際には、Kind 関数で得られた値と上記の定数とで比較を行う。
type MyStruct struct {
Id string
Code int
}
m := new(MyStruct)
rt := reflect.TypeOf(m)
kind := rt.Kind()
fmt.Println(kind == reflect.Array) // false
fmt.Println(kind == reflect.Struct) // false
fmt.Println(kind == reflect.Ptr) // true
(Type) Elem() reflect.Type
Type が保有しているメソッドの一つ。TypeOf などで取得した Type の(※)要素型を取得する。
※要素型・・・配列、チャネル、Map、ポインタ、スライスに格納される要素の型
Type の Kind が配列、チャネル、Map、ポインタ、スライス以外の場合は panic を引き起こす。
ValueOf などで得られる reflect.Value に対しても同名の関数が利用可能だが、そちらの返却値は型名ではなく値。
type MyStruct struct {
Id string
Code int
}
m := new(MyStruct)
rt := reflect.TypeOf(m)
fmt.Println(rt.Kind()) // ptr
elem := rt.Elem()
fmt.Println(elem) // main.MyStruct
strSlice := []string{"hogehoge"}
rt2 := reflect.TypeOf(strSlice)
fmt.Println(rt2.Kind()) // slice
elem2 := rt2.Elem()
fmt.Println(elem2) // string
str := "hogehoge"
rt3 := reflect.TypeOf(str)
fmt.Println(rt3.Kind()) // string
elem3 := rt3.Elem()
fmt.Println(elem3) // panic: reflect: Elem of invalid type string
ValueOf(interface{}) reflect.Value
引数に与えられた値について Value 型として初期化された値を取得する。
Value も Kind メソッドを持ち、 ValueOf で返却された値は元の値の Kind を維持する。
type MyStruct struct {
Id string
Code int
}
m := &MyStruct{Id: "id01", Code: 1}
rv := reflect.ValueOf(m)
fmt.Printf("type: %T, value: %v\n", rv, rv) // type: reflect.Value, value: &{id01 1}
fmt.Println(rv.Kind()) // ptr
str := "hoge"
rv2 := reflect.ValueOf(str)
fmt.Printf("type: %T, value: %v\n", rv2, rv2) // type: reflect.Value, value: hoge
fmt.Println(rv2.Kind()) // string
(Value) Indirect(reflect.Value) reflect.Value
ValueOf などで得られた reflect.Value の実体の値を参照する。 Kind が ptr である必要がある。
type MyStruct struct {
Id string
Code int
}
m := &MyStruct{Id: "id01", Code: 1}
rv := reflect.ValueOf(m)
indirect := reflect.Indirect(rv)
fmt.Println(indirect) // {id01 1}
(Value) Set(reflect.Value)
Value のメソッドであり、レシーバに対して引数で与えられた値を代入する。
事前に CanSet 関数で代入可能かどうかを検証すること。
type MyStruct struct {
Id string
Code int
}
target := new(MyStruct)
rvTarget := reflect.ValueOf(target)
indirect := reflect.Indirect(rvTarget)
fmt.Println(target) // &{ 0}
m := MyStruct{Id: "id01", Code: 1}
rvm := reflect.ValueOf(m)
indirect.Set(rvm)
fmt.Println(target) // &{id01 1}
Discussion