PR

Go言語(Golang)で型の構造やメタ情報を扱うためのreflectパッケージについて

2. 基礎

こんにちは。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」が含まれていたら、このパッケージに関するエラーというのが判別できると思います。

また、開発者向けのツールやライブラリ、そしてフレームワークなどを作る際にはこのパッケージを利用することになると思うので、そういったものを作りたい場合はぜひ参考にしてみて下さい。

 

この記事を書いた人
Tomoyuki

SE→ブロガーを経て、現在はSoftware Engineer(Web/Gopher)をしています!

Tomoyukiをフォローする
2. 基礎
スポンサーリンク
Tomoyukiをフォローする

コメント

タイトルとURLをコピーしました