2

(この質問のフォローアップとして:ネストされた構造体初期化リテラル)。

簡単に記述できるリテラルで構造体を初期化できるようになったので、コードの後半で親構造体のメンバーにアクセスする必要がありますが、具体的な派生型はわかりません。こんな感じです:

type A struct {
    MemberA string
}

type B struct {
    A
    MemberB string
}

そして、私はそれを次のように使用します:

b := B {
    A: A { MemberA: "test1" },
    MemberB: "test2",
}
fmt.Printf("%+v\n", b)

var i interface{} = b

// later in the code, I only know that I have something that has a nested A,
// I don't know about B (because A is in a library and B is in the 
// calling code that uses the library).

// so I want to say "give me the A out of i", so I try a type assertion

if a, ok := i.(A); ok {
    fmt.Printf("Yup, A is A: %+v\n", a)
} else {
    fmt.Printf("Aristotle (and John Galt) be damned! A is NOT A\n")
}

// no go

私が見るオプションは次のとおりです。

  • リフレクションを使用して "A" というメンバーを探し、それが適切な型であると仮定してそれを使用できます。これは実行可能ですが、効率が悪く、確かに「不格好」です。

  • HasA { Aval() A }呼び出し元に ( A のインスタンスを返す類似の) インターフェイスを実装するように要求することができます。

  • もう 1 つのポイントは、呼び出し元に A 値を渡させることができるということです (つまり、上記の例では、var i interface{} = bbecome var i A = b.A)。しかし、何が起こっているのかというと、私は実際に B のメンバーを動的に繰り返し処理し、それらを処理するため、そのためにはより多くの「派生」型が必要です。(これは、なぜ私がこれに遭遇したのかという背景にすぎず、質問の技術的な回答には関係ないため、質問から省略しました。)

Java の場合のように、「A にキャスト」できれば素晴らしいと思います。それを行うためのよりエレガントな方法はありますか。

4

4 に答える 4

2

不明な型 b がある場合、埋め込みフィールドを掘り出す唯一の方法は、リフレクションを使用することです。

それはそれほど不格好ではありません:

// obviously missing various error checks
t := reflect.ValueOf(i)
fmt.Printf("%+v\n", t.FieldByName("A").Interface().(A))

構造体の埋め込みは継承ではなく、継承として使用しようとすると、このような問題が引き続き発生します。go で一般的なポリモーフィズムを実現する方法は、インターフェイスを使用することです。

この状況を処理する最もクリーンな方法は、処理するフィールドに適切なアクセサ メソッドを備えた共通のインターフェイスを使用することだと思います。たとえば、実際の応答ヘッダーにアクセスするために使用されるメソッドhttp.ResponseWriterを持つstdlib の例が表示されます。Header()

于 2013-10-11T21:04:40.633 に答える
0

これは私にとってはうまくいきました。あなたが望むように直接キャストしていませんが、正しいオブジェクトインスタンスを提供します

fmt.Printf("It's", i.(B).A)

それが役立つことを願っています!

于 2013-10-11T21:04:25.097 に答える