目次 †概要 †reflect パッケージを使用して任意のインスタンスの生成や構造体からの値取得、セットなどを行う方法を記載する。 インスタンスの取得とメソッドの実行 †インスタンスの取得 †TODO: https://pkg.go.dev/reflect#Value.MethodByName
メソッドの実行 †TODO: https://pkg.go.dev/reflect#Value.Call
構造体のインスタンスを扱う †構造体から値を取得する †package main import ( "fmt" "reflect" ) type Person struct { Name string Age int } type Employee struct { Person EmpCode string } func main() { emp := Employee{} emp.Name = "Sample Taro" emp.Age = 30 emp.EmpCode = "TEST001" // 解析 myParse(&emp) } func getRef(input interface{}) (reflect.Type, reflect.Value) { rt := reflect.TypeOf(input) rv := reflect.ValueOf(input) if rt.Kind() == reflect.Ptr { rt = rt.Elem() rv = rv.Elem() } return rt, rv } func myParse(input interface{}) { rt, rv := getRef(input) for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) refName := f.Name refValue := rv.FieldByName(f.Name) if f.Type.Kind() == reflect.Struct { // 継承したフィールドの場合は再帰 myParse(refValue.Addr().Interface()) continue } // フィールド名と値を表示 fmt.Printf("%s = %v\n", refName, refValue.Interface()) } } 実行結果 Name = Sample Taro Age = 30 EmpCode = TEST001 構造体に値をセットする †package main import ( "fmt" "reflect" ) type Person struct { Name string Age int } type Employee struct { Person EmpCode string } func main() { emp := Employee{} emp.Name = "Sample Taro" emp.Age = 30 emp.EmpCode = "TEST001" // 値を変更する changeVal(&emp) fmt.Printf("emp.EmpCode: %s\n", emp.EmpCode) fmt.Printf("emp.Age : %d\n", emp.Age) } func getRef(input interface{}) (reflect.Type, reflect.Value) { rt := reflect.TypeOf(input) rv := reflect.ValueOf(input) if rt.Kind() == reflect.Ptr { rt = rt.Elem() rv = rv.Elem() } return rt, rv } func changeVal(input interface{}) { rt, rv := getRef(input) for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) refName := f.Name refValue := rv.FieldByName(f.Name) fmt.Printf("refName: %s, %v\n", refName, refValue.Type()) if f.Type.Kind() == reflect.Struct { // 継承したフィールドの場合は再帰 changeVal(refValue.Addr().Interface()) continue } if refName == "Age" { setValue(refValue, 32) } else if refName == "EmpCode" { setValue(refValue, "XYZ") } } } func setValue(refValue reflect.Value, val interface{}) { typeName := refValue.Type().Name() if !refValue.CanSet() { fmt.Println("Canot set!") return } switch typeName { case "bool": refValue.SetBool(val.(bool)) case "int": refValue.SetInt(int64(val.(int))) case "int8": refValue.SetInt(int64(val.(int8))) case "int16": refValue.SetInt(int64(val.(int16))) case "int32": refValue.SetInt(int64(val.(int32))) case "int64": refValue.SetInt(val.(int64)) case "float32": refValue.SetFloat(float64(val.(float32))) case "float64": refValue.SetFloat(val.(float64)) case "string": refValue.SetString(val.(string)) } } 実行結果 refName: Person, main.Person refName: Name, string refName: Age, int refName: EmpCode, string emp.EmpCode: XYZ emp.Age : 32 構造体からタグを取得する †package main import ( "fmt" "reflect" ) var TARGET_TAGS = []string{"mytag1", "mytag2", "mytag3"} type Person struct { Name string `mytag1:"test1"` Age int } type Employee struct { Person EmpCode string `mytag2:"test2" mytag3:"test3"` } func main() { emp := Employee{} emp.Name = "Sample Taro" emp.Age = 30 emp.EmpCode = "TEST001" // タグを取得する getTag(&emp) } func getRef(input interface{}) (reflect.Type, reflect.Value) { rt := reflect.TypeOf(input) rv := reflect.ValueOf(input) if rt.Kind() == reflect.Ptr { rt = rt.Elem() rv = rv.Elem() } return rt, rv } func getTag(input interface{}) { rt, rv := getRef(input) for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) refName := f.Name refValue := rv.FieldByName(f.Name) if f.Type.Kind() == reflect.Struct { // 継承したフィールドの場合は再帰 getTag(refValue.Addr().Interface()) continue } for _, tagName := range TARGET_TAGS { if tagValue, exist := f.Tag.Lookup(tagName); exist { fmt.Printf("%s, %s, %s\n", refName, tagName, tagValue) } } } } 実行結果 Name, mytag1, test1 EmpCode, mytag2, test2 EmpCode, mytag3, test3 |