そこで、Go(golang)でリフレクションを開始するのに役立つコードを見つけましたが、基本的な構造体とそのフィールドからmap[string]string
を作成できるように、基礎となる値を取得するのに苦労しています。
最終的には、結果をmap[string]interface{}
にしたいと思いますが、この1つの問題が私を阻んでいます。
私が現在持っているコード:
package main
import (
"fmt"
"reflect"
)
type Foo struct {
FirstName string `tag_name:"tag 1"`
LastName string `tag_name:"tag 2"`
Age int `tag_name:"tag 3"`
}
func inspect(f interface{}) map[string]string {
m := make(map[string]string)
val := reflect.ValueOf(f).Elem()
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
f := valueField.Interface()
val := reflect.ValueOf(f)
m[typeField.Name] = val.String()
}
return m
}
func dump(m map[string]string) {
for k, v := range m {
fmt.Printf("%s : %s\n", k, v)
}
}
func main() {
f := &Foo{
FirstName: "Drew",
LastName: "Olson",
Age: 30,
}
a := inspect(f)
dump(a)
}
コードの実行からの出力:
FirstName : Drew
LastName : Olson
Age : <int Value>
私が理解しているのは、FirstNameとLastNameの出力は実際のreflect.Valueオブジェクトですが、文字列の場合、valueのString()メソッドは基になるStringを出力するだけです。 intを取得して文字列に変更したいのですが、relfectパッケージのドキュメントからは、その方法がすぐにはわかりません。
Soo .... golangのreflect.Valueから基になる値を取得するにはどうすればよいですか?
値を解析する方法の良い例は、fmt
パッケージです。 このコード を参照してください。
上記のコードを使用して問題に一致させると、次のようになります。
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
m[typeField.Name] = strconv.FormatInt(val.Int(), 10)
case reflect.String:
m[typeField.Name] = val.String()
// etc...
}
基本的に、すべての 利用可能な種類 を確認する必要があります。
順調に進んでいるようです。あなたのコードで私が見ている問題は、値について仮定することです。つまり、いつElem()
を呼び出すか、そして何回(ポインタを解決するために)するかを意味します。これを知るには、reflect.Kind
を見る必要があります。値はreflect.Ptr
ですか?次にElem()
を使用します。
val.Interface()
/val.String()
/val.Int()
の値を取得したら、必要に応じて値を変換できます。使用するものはreflect.Kind
に依存します。 int
をstring
との間で変換するには、strconv
パッケージを使用する必要があります。
encoding/json
およびencoding/xml
パッケージは、すでにこの種の作業を行っています。ソースコードはいくつかの素晴らしい例を提供します。たとえば、 encoding/xml/read.go のcopyValue
と encoding/xml/marshal.go のmarshalSimple
を見てください。 。
これは、Go 1.5(2015年8月)で行う方が簡単です。 review 8731 および commit 049b89d by Rob Pike(robpike
) を参照してください。
fmt
:_reflect.Value
_を特別に扱う-保持する値として
これにより、Reflect.Value()
引数の実際の値を出力できます。
_
reflect.Value
_がPrintf
(など)に渡されると、fmt
はString
メソッドを呼び出しましたが、そのメソッドはその内容を公開しません。
コンテンツを取得するために、Value.Interface()
を呼び出すことができますが、Value
がエクスポートされていないか、禁止されている場合、これは違法です。このCLは、
fmt
パッケージに些細な変更を加えることで状況を改善します。_reflect.Value
_を引数として見ると、_reflect.Value
_をパッケージ内で行うのとまったく同じように扱います。
これは、常にValue
の内容をthatがPrintf
の引数であるかのように出力することを意味します。これは間違いなく重大な変更ですが、これは真の改善であり、このパッケージからフォーマットされた出力に対して行った他の多くの微調整よりも重大な改善ではないと思います。