やる気がストロングZERO

やる気のストロングスタイル

【Go】interface{}、reflectionについて調べたメモ

Goで「型は異なるが共通する処理(型が違うだけで、行いたいことは共通)」を書こうとしたとき、どうやればいいのかよくわからなかった。

C#だとジェネリクスとか使う感じのやつ。

Goだと引数をinterface{}でうけとって、reflectionを使ってなんやかんややる感じっぽい。

reflectionをどの様に使えばどのようなことができるのかを調べた
参考)https://blog.golang.org/laws-of-reflection

サンプルケース:「map[フィールド名]値」を使ってフィールド値をセットする関数を作る

type BaseHuman struct {
    Id int
}

type Human struct {
    Name string
    Age  int
    BaseHuman
}


// 「map[フィールド名]値」を使ってフィールド値をセットする。どんな型でも処理できる。
func SetValueFromMap(i interface{}, values map[string]interface{}) {
    structureElem := reflect.ValueOf(i).Elem() // iはポインタ型なのでElem()で値を取得する。
    for key, value := range values {
        field := structureElem.FieldByName(key) // keyでフィールドオブジェクトを取得する
        field.Set(reflect.ValueOf(value)) // Set()で値をセットする。(値がハッキリしてるなら(例えばintとか)SetInt()とかを使っても良さげ)
    }
}

// 実行テスト
func TestSetValueFromMap(t *testing.T) {
    human := Human{}

    // mapでフィールド名と値データを用意
    values := map[string]interface{}{
        "Id":   100,
        "Name": "太郎",
        "Age":  10,
    }

    // 構造体のポインタとデータmapを渡すと、構造体の対応するフィールドに値をセットしてくれる。
    SetValueFromMap(&human, values)
    assert.Equal(t, 100, human.Id)
    assert.Equal(t, "太郎", human.Name)
    assert.Equal(t, 10, human.Age)
}