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]
}
*/
}
}
}