目次 †概要 †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 |