これがコンパイルに失敗する理由について私は混乱しています:
不可能な型アサーション:FazはFooを実装しません(Barメソッドにはポインターレシーバーがあります)
faz.BarのレシーバーをFazポインターではなくFaz値にすると、コンパイルはうまくいきますが、値がコピーされないようにポインターレシーバーを使用する方が常に良いと思いましたか?
package main
import (
"log"
)
func main() {
foo := New().(Faz)
log.Println(foo)
}
type Foo interface {
Bar() string
}
func New() Foo {
return &Faz{}
}
type Faz struct {
}
func (f *Faz) Bar() string {
return `Bar`
}
それはだから *Faz
not Faz
。
func main() {
foo := New().(*Faz)
log.Println(foo)
}
この質問に対する答えは、文法に対するより遡及的なアプローチと、ソフトウェアエンジニアリングを通じてそれをどのように実装するかが必要だと思います。 (過剰な簡略化を許す)
最初に、types
とは何かを簡単にフラッシュバックしますか?
これらは、コンパイラロジックが上にあるメモリブロックです。 array
がstring
と異なるのは、コンパイラがこれらのメモリブロックでできることです。 (さらに深く考えると、_strongly typed
_言語と_dynamically typed
_言語の真の違いに気付くかもしれません。)
次に、ポインタは発言ごとに独自のタイプであることを認識する必要があります。
_*variable
_は、variable
とは異なるメモリブロック(別名)です。コンパイラは、_*variable
_の内容が、宣言の右側にあるタイプのメモリブロックへのアドレスと、それが課す他の制限/機能であると常に想定しているだけです。
次に、インターフェースとは何かをおさらいしましょう。
疑似科学的定義:ファーストクラス市民が特定のタイプであるための一連の要件。ソフトウェアエンジニアリングに変換-同じメモリ構造を持つメモリのブロック(タイプ)(構造パッキングに戻る)契約で説明されているように関連付けられている(interface
)は、契約で言及されているtype nameと同様に渡すことができます。
今、あなたはあなたが言うときにそれを実現し始めるかもしれません
func (f *Faz) Bar() string
は、関数を保持するf
のメモリブロックです。ここで、f
のタイプは、_Faz
どこのエリア
func (f Faz) Bar() string
はf
のメモリブロックです。f
のタイプはFaz
です
_*Faz
_型の変数が契約を満たしていると言っているとき、どのようにしてFaz
型の変数がコードのインターフェイス型として修飾されると仮定できますか?誰があなたの契約を満たし、そのタイプだけがコード内のインターフェースタイプを引き受けることができるかを選択します。