reflectで動的に型を判定

プログラム実行中に、動的に型の情報などを判別する技術( リフレクション(reflection) )について確認します。Goでは、reflectパッケージを利用して実現できます。利用機会は少ないですし、必要なければ利用しないほうが良い機能ですが、簡単に概要だけ確認します。

reflect.Value型 の値を取得

reflect.ValueOf関数reflect.Value型の値 を取得します。

その後、reflect.ValueKindメソッド で型情報を確認します。

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name string
	Age  int
}

func test(i interface{}) {
	// reflect.Value型の値を取得
	v := reflect.ValueOf(i)
	fmt.Printf("v.Kind()=%v\n\n", v.Kind())
}

func main() {
	fmt.Println("int")
	test(100)

	fmt.Println("string")
	test("hello")

	fmt.Println("slice")
	test([]int{1, 2, 3, 4, 5, 6, 7, 8})

	fmt.Println("map")
	test(map[string]int{"aa": 111, "bb": 222})

	fmt.Println("struct")
	test(User{"yamada", 27})

	fmt.Println("ptr")
	i := 100
	test(&i)
}
int
v.Kind()=int

string
v.Kind()=string

slice
v.Kind()=slice

map
v.Kind()=map

struct
v.Kind()=struct

ptr
v.Kind()=ptr

reflect.Type型 のメソッド
( 型ごとに利用できるメソッドが異なる )

reflect.ValueTypeメソッドreflect.Type型の値 を取得します。

reflect.Type型 で利用できるメソッドは、型ごとに異なります。

以下例で利用している NumFieldメソッド Fieldメソッドstruct 以外で利用すると panic となります。

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name string "xxx"
	Age  int    "yyy"
}

func test(i interface{}) {
	// reflect.Value型の値を取得
	v := reflect.ValueOf(i)
	fmt.Printf("v.Kind()=%v\n\n", v.Kind())

	if v.Kind() == reflect.Struct {
		// reflect.Type型の値を取得
		t := v.Type()
		for i := 0; i < t.NumField(); i++ {
			sf := t.Field(i)
			fmt.Printf("sf.Index=%v\n", sf.Index)
			fmt.Printf("sf.Name=%v\n", sf.Name)
			fmt.Printf("sf.Type=%v\n", sf.Type)
			fmt.Printf("sf.Tag=%v\n", sf.Tag)
		}
	}
}

func main() {
	fmt.Println("struct")
	test(User{"yamada", 27})
}
struct
v.Kind()=struct

sf.Index=[0]
sf.Name=Name
sf.Type=string
sf.Tag=xxx
sf.Index=[1]
sf.Name=Age
sf.Type=int
sf.Tag=yyy

参考