#author("2024-02-04T06:39:23+00:00","","")
#author("2024-02-04T15:40:38+09:00","","")
#mynavi(Go言語)
#setlinebreak(on);

* 目次 [#g9a6cd31]
#contents

* 概要 [#i54f6bd0]
#html(<div class="pl10">)

reflect パッケージを使用して任意のインスタンスの生成や構造体からの値取得、セットなどを行う方法を記載する。
#html(</div>)

* インスタンスの取得とメソッドの実行 [#h638e698]
#html(<div class="pl10">)

** インスタンスの取得 [#k7d7664f]
#html(<div class="pl10">)

#TODO(){{
https://pkg.go.dev/reflect#Value.MethodByName
}};

#html(</div>)

** メソッドの実行 [#ua246c6d]
#html(<div class="pl10">)

#TODO(){{
https://pkg.go.dev/reflect#Value.Call
}};

#html(</div>)

#html(</div>)

* 構造体のインスタンスを扱う [#yce5605a]
#html(<div class="pl10">)

** 構造体から値を取得する [#ka729a2d]
#html(<div class="pl10">)
#mycode2(){{
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())
    }
}
}}

実行結果
#myterm2(){{
Name = Sample Taro
Age = 30
EmpCode = TEST001
}}


#html(</div>)

** 構造体に値をセットする [#d5764545]
#html(<div class="pl10">)

#mycode2(){{
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))
    }
}
}}

実行結果
#myterm2(){{
refName: Person, main.Person
refName: Name, string
refName: Age, int
refName: EmpCode, string
emp.EmpCode: XYZ
emp.Age    : 32
}}

#html(</div>)

** 構造体からタグを取得する [#y2c06bc2]
#html(<div class="pl10">)

#mycode2(){{
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)
            }
        }
    }
}
}}

実行結果
#myterm2(){{
Name, mytag1, test1
EmpCode, mytag2, test2
EmpCode, mytag3, test3
}}


#html(</div>)

#html(</div>)

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS