web-dev-qa-db-ja.com

インターフェイスをポインターレシーバーで実装できないのはなぜですか

これがコンパイルに失敗する理由について私は混乱しています:

不可能な型アサーション: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`
}
51
Daniel Robinson

それはだから *Faz not Faz

func main() {
    foo := New().(*Faz)
    log.Println(foo)
}
52
OneOfOne

この質問に対する答えは、文法に対するより遡及的なアプローチと、ソフトウェアエンジニアリングを通じてそれをどのように実装するかが必要だと思います。 (過剰な簡略化を許す)


最初に、typesとは何かを簡単にフラッシュバックしますか?
これらは、コンパイラロジックが上にあるメモリブロックです。 arraystringと異なるのは、コンパイラがこれらのメモリブロックでできることです。 (さらに深く考えると、_strongly typed_言語と_dynamically typed_言語の真の違いに気付くかもしれません。)

次に、ポインタは発言ごとに独自のタイプであることを認識する必要があります。
_*variable_は、variableとは異なるメモリブロック(別名)です。コンパイラは、_*variable_の内容が、宣言の右側にあるタイプのメモリブロックへのアドレスと、それが課す他の制限/機能であると常に想定しているだけです。

次に、インターフェースとは何かをおさらいしましょう。
疑似科学的定義:ファーストクラス市民が特定のタイプであるための一連の要件。ソフトウェアエンジニアリングに変換-同じメモリ構造を持つメモリのブロック(タイプ)(構造パッキングに戻る)契約で説明されているように関連付けられている(interface)は、契約で言及されているtype nameと同様に渡すことができます。


今、あなたはあなたが言うときにそれを実現し始めるかもしれません

func (f *Faz) Bar() stringは、関数を保持するfのメモリブロックです。ここで、fのタイプは、_Faz

どこのエリア

func (f Faz) Bar() stringfのメモリブロックです。fのタイプはFazです

_*Faz_型の変数が契約を満たしていると言っているとき、どのようにしてFaz型の変数がコードのインターフェイス型として修飾されると仮定できますか?誰があなたの契約を満たし、そのタイプだけがコード内のインターフェースタイプを引き受けることができるかを選択します。

4
dtx