reflectを使用していて、Type()とKind()の違いって何だっけ?となったり、特に構造体でTypeとValueの使い方で混乱するので、いろいろな型での実行結果をまとめてみました。解説記事も書いていこうと思います。
(ソースコードがうまいこと色付けされてないですね…方法調べてなおします) WP Githuber MDプラグインを使ってるんですが、プラグインのSyntax HighlightをONにすればOKでした(既存の投稿に反映させるには投稿の更新が必要)。

関連記事:Goのreflectを理解する

package main

import (
    "fmt"
    "reflect"
)

type CType int

const (
    Sabatora CType = iota
    Kizitora
)

func (t CType) String() string {
    switch t {
    case Sabatora:
        return "Sabatora"
    case Kizitora:
        return "Kizitora"
    }
    return ""
}

type Cat struct {
    Name    string `tag:"name"`
    Age     *int
    CatType CType
    Family  []Person
    Color   map[string]string
}

type Person struct {
    Name string
    Age  int
}

func main() {

    var age int
    var cat Cat

    age = 2
    cat = Cat{
        Name:    "Kawaii",
        Age:     &age,
        CatType: Kizitora,
        Family: []Person{
            {
                Name: "kainushi1",
                Age:  29,
            },
            {
                Name: "kainushi2",
                Age:  30,
            },
        },
        Color: map[string]string{
            "eye": "yellow",
            "pad": "black",
        },
    }

    // string
    fmt.Println("# string")
    {
        t := reflect.TypeOf(cat.Name)
        v := reflect.ValueOf(cat.Name)

        fmt.Printf("t.Kind: %s\n", t.Kind())   // t.Kind: string
        fmt.Printf("t.Type: %s\n", t.String()) // t.Type: string
        fmt.Printf("v.Kind: %s\n", v.Kind())   // v.Kind: string
        fmt.Printf("v.Type: %s\n", v.Type())   // v.Type: string

        if v.Kind() == reflect.String {
            fmt.Printf("value: %s\n", v.String()) // value: Kawaii
        }

        if value, ok := v.Interface().(string); ok {
            fmt.Printf("value: %s\n", value) // value: Kawaii
        }
    }

    // int
    fmt.Println("# int")
    {
        t := reflect.TypeOf(cat.Family[0].Age)
        v := reflect.ValueOf(cat.Family[0].Age)

        fmt.Printf("t.Kind: %s\n", t.Kind())   // t.Kind: int
        fmt.Printf("t.Type: %s\n", t.String()) // t.Type: int
        fmt.Printf("v.Kind: %s\n", v.Kind())   // v.Kind: int
        fmt.Printf("v.Type: %s\n", v.Type())   // v.Type: int

        if v.Kind() == reflect.Int && v.CanInt() {
            fmt.Printf("value: %d\n", v.Int()) // value: 29
        }

        if value, ok := v.Interface().(int); ok {
            fmt.Printf("value: %d\n", value) // value: 29
        }
    }

    // pointer
    fmt.Println("# pointer")
    {
        t := reflect.TypeOf(cat.Age)
        v := reflect.ValueOf(cat.Age)

        fmt.Printf("t.Kind: %s\n", t.Kind())   // t.Kind: ptr
        fmt.Printf("t.Type: %s\n", t.String()) // t.Type: *int
        fmt.Printf("v.Kind: %s\n", v.Kind())   // v.Kind: ptr
        fmt.Printf("v.Type: %s\n", v.Type())   // v.Type: *int

        if v.Kind() == reflect.Ptr {
            fmt.Println("this is a pointer") // this is a pointer
        }

        if value, ok := v.Interface().(*int); ok {
            fmt.Printf("value: %d\n", *value) // value: 2
        }

        if value, ok := v.Elem().Interface().(int); ok {
            fmt.Printf("value: %d\n", value) // value: 2
        }
    }

    // enum
    fmt.Println("# enum")
    {
        t := reflect.TypeOf(cat.CatType)
        v := reflect.ValueOf(cat.CatType)

        fmt.Printf("t.Kind: %s\n", t.Kind())   // t.Kind: int
        fmt.Printf("t.Type: %s\n", t.String()) // t.Type: main.CType
        fmt.Printf("v.Kind: %s\n", v.Kind())   // v.Kind: int
        fmt.Printf("v.Type: %s\n", v.Type())   // v.Type: main.CType

        if v.Kind() == reflect.Int && v.CanInt() {
            fmt.Printf("value: %d\n", v.Int()) // value: 1
        }

        if value, ok := v.Interface().(int); ok {
            fmt.Printf("value: %d\n", value) //
        } else {
            fmt.Println("this is not an integer") // this is not an integer
        }

        if value, ok := v.Interface().(CType); ok {
            fmt.Printf("value: %d\n", value) // value: 1
            fmt.Printf("value: %s\n", value) // value: Kizitora
        }
    }

    // array, slice
    fmt.Println("# array")
    {
        t := reflect.TypeOf(cat.Family)
        v := reflect.ValueOf(cat.Family)

        fmt.Printf("t.Kind: %s\n", t.Kind())          // t.Kind: slice
        fmt.Printf("t.Type: %s\n", t.String())        // t.Type: []main.Person
        fmt.Printf("v.Kind: %s\n", v.Kind())          // v.Kind: slice
        fmt.Printf("v.Type: %s\n", v.Type().String()) // v.Type: []main.Person

        if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
            fmt.Printf("length: %d\n", v.Len()) // length: 2
            for i := 0; i < v.Len(); i++ {
                value := v.Index(i)
                fmt.Printf("index: %d, item: %+v\n", i, value.Interface())
                // index: 0, item: {Name:kainushi1 Age:29}
                // index: 1, item: {Name:kainushi2 Age:30}
            }
        }

        if value, ok := v.Interface().([]Person); ok {
            fmt.Printf("value: %+v\n", value) // value: [{Name:kainushi1 Age:29} {Name:kainushi2 Age:30}]
        }
    }

    // map
    fmt.Println("# map")
    {
        t := reflect.TypeOf(cat.Color)
        v := reflect.ValueOf(cat.Color)

        fmt.Printf("t.Kind: %s\n", t.Kind())   // t.Kind: map
        fmt.Printf("t.Type: %s\n", t.String()) // t.Type: map[string]string
        fmt.Printf("v.Kind: %s\n", v.Kind())   // v.Kind: map
        fmt.Printf("v.Type: %s\n", v.Type())   // v.Type: map[string]string

        if v.Kind() == reflect.Map {
            iter := v.MapRange()
            for iter.Next() {
                fmt.Printf("key: %s, value: %s\n", iter.Key(), iter.Value())
            }
            // key: eye, value: yellow
            // key: pad, value: black

            keys := v.MapKeys()
            for _, key := range keys {
                fmt.Printf("key: %s, value: %s\n", key, v.MapIndex(key))
            }
            // key: eye, value: yellow
            // key: pad, value: black
        }

        if value, ok := v.Interface().(map[string]string); ok {
            fmt.Printf("value: %+v\n", value) // value: map[eye:yellow pad:black]
        }
    }

    // struct
    fmt.Println("# struct")
    {
        t := reflect.TypeOf(cat)
        v := reflect.ValueOf(cat)

        fmt.Printf("t.Kind: %s\n", t.Kind())   // t.Kind: struct
        fmt.Printf("t.Type: %s\n", t.String()) // t.Type: main.Cat
        fmt.Printf("v.Kind: %s\n", v.Kind())   // v.Kind: struct
        fmt.Printf("v.Type: %s\n", v.Type())   // v.Type: main.Cat

        for i := 0; i < t.NumField(); i++ {
            name := t.Field(i).Name
            tp := t.Field(i).Type
            kind := t.Field(i).Type.Kind()

            fmt.Printf("t.Field.Name: %s\n", name)
            fmt.Printf("t.Field.Type: %s\n", tp)
            fmt.Printf("t.Field.Kind: %s\n", kind)
            // t.Field.Name: Name
            // t.Field.Type: string
            // t.Field.Kind: string

            // t.Field.Name: Age
            // t.Field.Type: *int
            // t.Field.Kind: ptr

            // t.Field.Name: CatType
            // t.Field.Type: main.CType
            // t.Field.Kind: int

            // t.Field.Name: Family
            // t.Field.Type: []main.Person
            // t.Field.Kind: slice

            // t.Field.Name: Color
            // t.Field.Type: map[string]string
            // t.Field.Kind: map
        }

        for i := 0; i < v.NumField(); i++ {
            name := v.Field(i).Type().Name()
            tp := v.Field(i).Type()
            kind := v.Field(i).Kind()
            fmt.Printf("v.Field.Name: %s\n", name)
            fmt.Printf("v.Field.Type: %s\n", tp)
            fmt.Printf("v.Field.Kind: %s\n", kind)

            // v.Field.Name: string
            // v.Field.Type: string
            // v.Field.Kind: string

            // v.Field.Name:
            // v.Field.Type: *int
            // v.Field.Kind: ptr

            // v.Field.Name: CType
            // v.Field.Type: main.CType
            // v.Field.Kind: int

            // v.Field.Name:
            // v.Field.Type: []main.Person
            // v.Field.Kind: slice

            // v.Field.Name:
            // v.Field.Type: map[string]string
            // v.Field.Kind: map
        }

        if value, found := t.FieldByName("Name"); found {
            fmt.Printf("Field name: %s\n", value.Name)             // Field name: Name
            fmt.Printf("Field value: %s\n", v.FieldByName("Name")) // Field value: Kawaii
            tag := value.Tag
            fmt.Printf("Field tag: %s\n", tag.Get("tag")) // Field tag: name
            if t, ok := tag.Lookup("tag"); ok {
                fmt.Printf("Field tag: %s\n", t) // Field tag: name
            }
        }

        if !v.FieldByName("hogehoge").IsValid() {
            fmt.Println("hogehoge was not found") // hogehoge was not found
        }

        if value, ok := v.Interface().(Cat); ok {
            fmt.Printf("value: %+v\n", value)
            /*
                value: {
                    Name:Kawaii
                    Age:0xc0000120a0
                    CatType:Kizitora
                    Family:[{Name:kainushi1 Age:29} {Name:kainushi2 Age:30}]
                    Color:map[eye:yellow pad:black]
                }
            */
        }
    }
}

にほんブログ村 IT技術ブログへ

投稿者 iris

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です