はじめに
reflectでゴニョゴニョしたいときに毎回沼にハマってすごく時間をつかうので、使うパターンをメモっておく。
随時更新(したい)です
それではレッツゴー
任意の値があるプリミティブ型か確認したい
if reflect.ValueOf(v).Kind() == reflect.Int64 { // v kind is int64 }
任意の値がある具象型か確認したい
単に v.(SomeStruct)
でもできるし v.(type)
で型switchしてもできる。基本はそっちを使うほうが無駄なコストがかからずよい。
何らかの都合でreflect.Valueやreflect.Typeしか知らないなら以下のようにできる
if reflect.TypeOf(v) == reflect.TypeOf(SomeStruct{}) { // v type is SomeStruct }
任意の値がポインタだったらそのポインタが示す値を取得する
rv := reflect.Elem()
任意のstructのフィールドのタグを取得
rt := reflect.TypeOf(v) size := rt.NumField() for i := 0; i < size; i++ { tag := rt.Field(i).f.Tag.Get("tag_name") }
structの任意のフィールドがポインタでnilだったら、その型の空の値で埋めたい
rv := reflect.ValueOf(v).Elem().Field(fieldNum)
if rv.Kind() == reflect.Ptr && rv.IsNil() {
rv.Set(reflect.New(rv.Type().Elem()))
}
ある型の空値のポインタを作りたい
ptr := reflect.New(reflect.TypeOf(v)).Interface()
型不明のsliceに型不明の要素をappendしたい
入力もreflect.Valueであり、かつappendしたい要素もreflect.Valueだ!ゴリゴリやらねば!みたいなときはしたいはず。型が一致してないとpanicします
sliceはあるslice型のreflect.Valueで、elemはそれに一致する型で値を作って値を埋めて突っ込むことを想定
slice := reflect.ValueOf(v) elem := reflect.New(rv.Type().Elem()).Elem() bindElem(elem, data) rv = reflect.Append(rv, elem)
ある型がinterfaceを実装しているか確認
var iface someInterface rt := reflect.TypeOf(v) if rt.Implements(reflect.TypeOf(&iface).Elem()) { // v implements someInterface }
あるinterfaceの実装をすべて列挙したい
非公開な reflect.typelinks()
をつかえばできる。
//go:linkname
ディレクティブを使って非公開関数をよぶぞ!
これが一番闇っぽい
//go:linkname typelinks reflect.typelinks func typelinks() ([]unsafe.Pointer, [][]int32) //go:linkname rtypeOff reflect.rtypeOff func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer func getImplements(iface reflect.Type) ([]reflect.Value, error) { sections, offsets := typelinks() if len(sections) != 1 { return nil, fmt.Errorf("failed to get sections") } if len(offsets) != 1 { return nil, fmt.Errorf("failed to get offsets") } implements := make([]reflect.Value, 0) for i, base := range sections { for _, offset := range offsets[i] { typeAddr := rtypeOff(base, offset) typ := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&typeAddr))) if typ.Implements(iface) { implements = append(implements, reflect.New(typ.Elem())) } } } return implements, nil }