目的
ネストしているstruct内のすべての値を取得し、文字列連結したい
ユースケース
連結した文字列からハッシュを生成し、リクエストパラメータのチェックサムに使う
コード
package main
import (
"bytes"
"fmt"
"reflect"
"strconv"
)
// reflect.Value を返す関数
func toReflectValue(i interface{}) (reflect.Value, bool) {
rv, ok := i.(reflect.Value)
if !ok {
rv = reflect.ValueOf(i)
}
switch rv.Kind() {
case reflect.Ptr:
// ポインタ以外になるまで reflect.Indirect する
return toReflectValue(reflect.Indirect(rv))
case reflect.Struct:
return rv, true
}
// 構造体以外
return rv, false
}
func recursive(depth int, rv reflect.Value, str *bytes.Buffer) {
typ := rv.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
kind := field.Type.Kind()
value := rv.FieldByName(field.Name)
if kind != reflect.Ptr {
if kind == reflect.Struct {
recursive(depth+1, value, str)
} else {
switch kind.String() {
case "int":
s := value.Interface().(int)
str.WriteString(strconv.Itoa(s))
case "string":
str.WriteString(value.String())
}
}
}
}
}
func main() {
type Address struct {
name string
}
type User struct {
Name string
Age int
Address Address
}
user := User{"suzuki", 18, Address{"Tokyo"}}
rv, _ := toReflectValue(user)
str := bytes.Buffer{}
recursive(0, rv, &str)
fmt.Println(str.String())
}
結果
suzuki18Tokyo
その他
他の型への対応は、switch kind.String()
に追加する
参考
下記のコードに対して修正を加えました。感謝
https://golang.hateblo.jp/entry/2018/11/10/083000