-2

関数を変数に割り当てるとき、コンパイラが次の場合に完全な関数シグネチャの一致を必要とするのはなぜですか...

  • 変数の型は、パラメーターまたは戻り値が特定のインターフェースである関数であり、
  • 割り当てられる関数には別のインターフェースが必要ですが、期待されるインターフェースを組み込むインターフェースです。

この例を見てください...

  • Fooerインターフェースです
  • FooerBarerインターフェイスを埋め込むFooerインターフェイスです
  • *bar実装FooerBarer

http://play.golang.org/p/8NyTipiQak

    // Define a type that is a function that returns a Fooer interface
type FMaker func() Fooer

/* Define values of the FMaker type */

    // This works, because the signature matches the FMaker type
var fmake FMaker = func() Fooer {
    return &bar{}
}

    // This causes an error even though a FooerBarer is a Fooer
var fmake2 FMaker = func() FooerBarer {
    return &bar{}
}

ですから、私の質問は別の解決策ではなく、なぜコンパイラがこのように構築されているのかということです。

コンパイラは、を返すことによって、FooerBarerしたがって、を返していることを認識しFooer、割り当てを受け入れるように見えます。

それで...

  • コンパイラのこの厳密な動作の理由は何ですか?
  • どのような問題が解決されているか、危険が回避されていますか?
  • これが、変数FooerBarerへの代入で値を受け入れるコンパイラと異なるのはなぜですか?Fooer
4

1 に答える 1

3

簡単に言えば、FooerはFooerBarerではありません。どちらもインターフェイスタイプですが、異なるitableを指します。Fooerは、itablebeの最初のメソッドを持つことが保証されていますFoo() Fooer。FooerBarerでは、Bar() FooerBarer最初のメソッドとして持っている可能性があります。したがって、実行時にメソッドルックアップは間違ったメソッドを返します。

FooerBarerには常にFooerに必要なメソッドセットがあるため、FooerBarerからFooerへの変換はすべて成功することが保証されています。インターフェイス変換が機能する方法では、ランタイムは最初に受信したFooerBarerの実際のタイプ(バーなど)を検索し、次にbar / Fooerペアのitableを検索して、新しいインターフェイス値を作成します。

Goコードでは、これを明示的または暗黙的に発生させることができます。たとえばx := Fooer(myFooerBarer)。これにより、明示的な変換が行われ、新しいインターフェイス値がxに配置されます。タイプの関数がfunc(Fooer)あり、FooerBarerを渡した場合、変換は暗黙的に行われます。コンパイラーは変換を行い、その結果を関数呼び出しのパラメーターに割り当てます。

上記の場合、をに割り当てようとしfunc() FooerBarerていfunc() Fooerます。Goでは、自動変換のある割り当てはありません。ダブルをintに割り当てることはできません。基になるタイプが同じであっても、int64にtime.Durationを割り当てることはできません。この場合、関数を実行するたびに変換を実行できるように、関数をラップする必要があります。同じ基になるタイプ間の変換を自動で許可せず、関数を自動的にラップすることは少し一貫性がありません。

あなたが本当にこのようなことをする必要があるなら、簡単な答えがあります。関数をラップするだけです。

var fbmake = func() FooerBarer {
    return &bar{}
}

var fmake Fmaker = func() Fooer {
    return fbmake()
}
于 2012-10-27T23:35:30.103 に答える