こんにちは。Tomoyuki(@tomoyuki65)です。
普段の開発ではあまり必要になりませんが、例えば開発者用のツールやライブラリ、そしてフレームワークなどを作りたいというような場合は、入力値の型情報を調べる必要がでてきたりします。
そんな時にGo言語(Golang)では、「reflect」パッケージを使うことで、型の構造やメタ情報を扱うことが可能です。
この記事では、そんな「reflect」パッケージについてご紹介します。
Go言語(Golang)で型の構造やメタ情報を扱うためのreflectパッケージについて
Go言語(Golang)の「reflect」パッケージは、型情報や値を調べたり、操作したりするための標準パッケージです。
型情報を調べる
型情報を調べたい場合、「reflect.TypeOf」を使います。
package main
import (
"fmt"
"reflect"
)
func main() {
// int型の変数xを定義
var x int = 10
// 型情報を取得
t := reflect.TypeOf(x)
// ログ出力
fmt.Printf("変数xの型: %s\n", t)
}
実行結果
変数xの型: int
また、厳密な型ではなく、型の種類を調べたい場合は「Kind」メソッドを使います。
package main
import (
"fmt"
"reflect"
)
// 型定義
type MyType int
func main() {
// MyType型の変数xを定義
var x MyType = 10
// 型情報を取得
t := reflect.TypeOf(x)
// ログ出力
fmt.Printf("変数xの厳密な型: %s\n", t)
fmt.Printf("変数xの型の種類: %s\n", t.Kind())
}
実行結果
変数xの厳密な型: main.MyType
変数xの型の種類: int
例えばswitch文とKindメソッドを使うことで型判定が可能です。
package main
import (
"fmt"
"reflect"
)
// 型定義
type MyType int
func main() {
// MyType型の変数xを定義
var x MyType = 10
// 型情報を取得
t := reflect.TypeOf(x)
// 型判定
switch t.Kind() {
case reflect.Int:
fmt.Println("int型です。")
case reflect.String:
fmt.Println("string型です。")
default:
fmt.Println("対象外の型です。")
}
}
※reflectの判定用メソッドについては、他にも「Bool」、「Struct」、「Slice」、「Array」、「Map」、「Ptr」(ポインタ)、「Interface」などがあります。尚、型判定と言えば、interface型(any型)を使った際にtypeでキャストして型判定することがあったりしますが、今回ご紹介のreflectパッケージは一般的な開発用のものではないため、interface型(any型)の型判定ではtypeでキャストする方法を利用するようにして下さい。
実行結果
int型です。
値を調べる
型情報ではなく、値を調べたい場合は「reflect.ValueOf」を使います。
package main
import (
"fmt"
"reflect"
)
func main() {
// int型の変数xを定義
var x int = 10
// 値情報を取得
v := reflect.ValueOf(x)
// ログ出力
fmt.Printf("変数xの値: %d\n", v.Int())
}
実行結果
変数xの値: 10
また、ポインタおよび「Elem」メソッドと「Set」メソッドを使うことで値の書き換えも可能です。
package main
import (
"fmt"
"reflect"
)
func main() {
// int型の変数xを定義
var x int = 10
// 値情報を取得(ポインタを渡す)
v := reflect.ValueOf(&x)
// ポインタかを判定
if v.Kind() == reflect.Ptr {
// ポインタが指している値を取得
v = v.Elem()
}
// 値の書き換え
v.SetInt(20)
// ログ出力
fmt.Printf("変数xの値: %d\n", v.Int())
}
実行結果
変数xの値: 20
構造体の情報を調べる
構造体の情報を調べたい場合は、「reflect.TypeOf」と「NumField」メソッドを使います。
package main
import (
"fmt"
"reflect"
)
// Userモデルの構造体の定義
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func main() {
// Userの定義
user := User{ID:1, Name:"田中太郎"}
// 型情報を取得
t := reflect.TypeOf(user)
// Userモデルの構造体情報を取得
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Printf("フィールド名:%s, 型:%s, メタ情報:%s\n", f.Name, f.Type, f.Tag.Get("json"))
}
}
実行結果
フィールド名:ID, 型:int, メタ情報:id
フィールド名:Name, 型:string, メタ情報:name
最後に
今回はGo言語(Golang)の「reflect」パッケージについてご紹介しました。
普段の開発で使うことはほぼ無いと思いますが、もし使っているライブラリのエラーメッセージに「reflect」が含まれていたら、このパッケージに関するエラーというのが判別できると思います。
また、開発者向けのツールやライブラリ、そしてフレームワークなどを作る際にはこのパッケージを利用することになると思うので、そういったものを作りたい場合はぜひ参考にしてみて下さい。



コメント