0

私は現在、golangs Reflect パッケージの動作に必死になっていますが、これはまったく一貫していないようです。

1)私が理解している限り、reflect.Value は基になる値へのポインタを持っているようです。たとえば、私が電話した場合

var s string
v1 := reflect.ValueOf(&s).Elem()
v2 := v1
v2.SetString("Hello World!")
fmt.Println(s)

「Hello World!」と表示されます。ただし、これは、Field() の呼び出しによって取得された Reflect.Value には当てはまらないようです。

val := ... //Assign a reflect.Value to it
nextval := val.Field(0) //Make sure that Field exists and is of type map
nextval = reflect.MakeMap(reflect.MapOf(KEY, ELEM))
nextval.SetMapIndex(Some_value_of_type_KEY, Something_of_type_ELEM)
fmt.Println(nextval.MapKeys()
fmt.Println(val.Field(index).MapKeys())

これは印刷します

[Some_value_of_type_KEY]
[]

これは大きな迷惑です。なぜこれが事実なのか誰にも分かりますか?

================================================== =

2) 機能を考える

func Test(v interface{}) {
    val := reflect.ValueOf(v)
    if val.Kind() != reflect.Struct {
        fmt.Println("It is a struct")
    }
}

構造体を引数として呼び出すと、「これは構造体です」と出力されます。ただし、値がアドレス指定できないため、val を使用して v 内のものに新しい値を割り当てることはできません。次の方法で回避します。

func Test(v interface{}) {
    val := reflect.ValueOf(&v).Elem()
    if val.Kind() != reflect.Struct {
        fmt.Println("This never get's printed!")
    }
}

According to the doc, I would assume, that by taking the '&' I use a pointer to v and by the call of Elem() I get the element it points to, therefore val.Kind() should still return the same thing. It doesn't. val.Kind() now is a reflect.Interface.

Is there a way of not having to go

valForTestingKind := reflect.ValueOf(v)
valForSettingNewValue := reflect.ValueOf(&v).Elem()

as this somehow feels wrong.

4

4 に答える 4

2

パート1:

に割り当てることによりnextval、元の との関連付けが解除されますval。代わりに、Set()メソッドを使用してください。

nextval.Set(reflect.MakeMap(reflect.MapOf(KEY, ELEM)))

Set()リフレクション ワールドでの代入に相当します。もちろん、reflect.ValueOf(&v).Elem()最初のコード例で行ったように、割り当て可能であることを確認する必要があります。


パート2:

ここでの問題は、別のレベルの間接性があることです。v型は interface{} であり、型が Kind 構造体である具体的な値を持っています。インターフェイスの型付きパラメーターを受け入れるすべての関数と同様に、 を呼び出すreflect.ValueOfと、パラメーターは自動的にその型に変換されます。ただし、インターフェイスを別のインターフェイスに変換すると、具体的な値が新しいインターフェイス タイプに再ボックス化されます。リボックスされる前のタイプの情報は失われます。例として、io.Writer を受け入れる関数は、呼び出し元の関数がそれを io.ReaderWriter と見なしたことを知りません。

このコンテキストでは、reflect.ValueOf は、os.File (何らかの構造体) を渡したのか、インターフェイスにボックス化されたファイルを渡したのかを判断できないことを意味します{}。os.File を渡したものと仮定し、種類の「構造体」を表示します。

ただし、interface{} へのポインターを渡す場合は、変更可能な interface{} 変数を渡すことになります。基礎となる具象型を渡していないため、重要な結果が生じます。.Set()元の具象型が許可するものだけでなく、何でもできます。インターフェース内の何も割り当てられないため、個々のフィールドを編集することもできません。{} 具象型が実際にポインターである場合は、4 番目の逆参照 ( .Elem()) を実行して、そこからフィールドを変更できます。

では、これはコードの観点から何を意味するのでしょうか?

//let v = an interface{} with a concrete type of SomeStruct
val := reflect.ValueOf(&v).Elem()
fmt.Println(val.Elem().Kind())                // struct
val.Elem().Field(0).Set(10)                   // PANIC! Field isn't assignable.
val.Set("a string which is not a SomeStruct")
fmt.Println(val.Elem().Kind())                // string

ここで例を作りました: http://play.golang.org/p/6MULn3KoNh

于 2013-06-30T06:47:37.217 に答える
1

2 番目のコード ブロックについてお話したいと思います。

val := ... //Assign a reflect.Value to it
nextval := val.Field(0) //Make sure that Field exists and is of type map
nextval = reflect.MakeMap(reflect.MapOf(KEY, ELEM))
nextval.SetMapIndex(Some_value_of_type_KEY, Something_of_type_ELEM)
fmt.Println(nextval.MapKeys()
fmt.Println(val.Field(index).MapKeys())

3 行目では、新しい別のオブジェクトを variable に再割り当てしていますnextval。nextval を再割り当てする代わりに、なんらかの設定メソッドを呼び出すべきではありませんか? 最初の例では呼び出しSetStringましたが、この例では変数を再割り当てしているだけなので、動作が異なる可能性があります。変数を再割り当てすると、nextvalは に接続されなくなりますval.Field(0)。また、何indexですか?

これで問題が説明されない場合は、質問を編集して、短い自己完結型の正しいコンパイル可能な例 ( SSCCE ) を含めてください。問題を確認するために、golang.org のフロント ページのテキスト ボックスに投稿できるようにしたいと考えています。可能であれば、常に SSCCE を投稿する必要があります。

于 2013-06-30T01:09:18.637 に答える
0

完全でコンパイル可能なコードを示していません。構造体へのポインターを渡しますか、それとも構造体を値で渡しますか? 後者の場合、リフレクションはそれを変更できません。

于 2013-06-30T01:14:50.427 に答える
0

マップに格納された値は、リフレクションを使用していない場合でもアドレス指定できません。

http://play.golang.org/p/wYLeJ3W4R2

http://play.golang.org/p/ttUGBVh1lc

https://groups.google.com/forum/#!topic/golang-nuts/jzjEXoc9FwU

https://groups.google.com/forum/#!topic/golang-nuts/V_5kwzwKJAY

于 2013-11-28T12:57:07.853 に答える