[解決済み] 「<type>はインターフェースへのポインターであり、インターフェースではない」混乱
質問
ちょっと変な問題があるんです。このコードのスニペットを見てください。
package coreinterfaces
type FilterInterface interface {
Filter(s *string) bool
}
type FieldFilter struct {
Key string
Val string
}
func (ff *FieldFilter) Filter(s *string) bool {
// Some code
}
type FilterMapInterface interface {
AddFilter(f *FilterInterface) uuid.UUID
RemoveFilter(i uuid.UUID)
GetFilterByID(i uuid.UUID) *FilterInterface
}
type FilterMap struct {
mutex sync.Mutex
Filters map[uuid.UUID]FilterInterface
}
func (fp *FilterMap) AddFilter(f *FilterInterface) uuid.UUID {
// Some code
}
func (fp *FilterMap) RemoveFilter(i uuid.UUID) {
// Some code
}
func (fp *FilterMap) GetFilterByID(i uuid.UUID) *FilterInterface {
// Some code
}
別のパッケージでは、次のようなコードになっています。
func DoFilter() {
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}
ランタイムは、以下の理由で、言及された行を受け付けません。
fieldfilter (type *coreinterfaces.FieldFilter) を type として使用することはできません。 fieldint.AddFilter の引数に *coreinterfaces.FilterInterface を指定してください。 *coreinterfaces.FilterInterface はインターフェースへのポインターであり、インターフェースではありません"
しかし、このコードを変更すると
func DoBid() error {
bs := string(b)
var ifilterfield coreinterfaces.FilterInterface
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
ifilterfield = fieldfilter
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(&ifilterfield)
}
すべて問題なく、アプリケーションをデバッグすると、本当に含まれているようです。
このトピックについては、少し混乱しています。このまったく同じ問題を議論している他のブログ記事やスタックオーバーフローのスレッドを見てみると、(たとえば これは または この なぜなら、fieldfilter と fieldmap は両方ともインターフェースの値ではなく、インターフェースへのポインターとして初期化されるからです。FieldInterfaceを宣言してそのインターフェイスの実装を割り当てないようにするために、ここで実際に何が起こるのかを理解することができません。これを行うためのエレガントな方法があるはずです。
解決方法は?
つまり、あなたはここで2つの概念を混同しているのです。 構造体へのポインタとインタフェースへのポインタは同じではありません。 インターフェースは構造体を直接格納することもできますし または 構造体へのポインタ 後者の場合、やはりインターフェースを直接使うだけです。 ではなく へのポインタです。 例えば
type Fooer interface {
Dummy()
}
type Foo struct{}
func (f Foo) Dummy() {}
func main() {
var f1 Foo
var f2 *Foo = &Foo{}
DoFoo(f1)
DoFoo(f2)
}
func DoFoo(f Fooer) {
fmt.Printf("[%T] %+v\n", f, f)
}
出力します。
[main.Foo] {}
[*main.Foo] &{}
https://play.golang.org/p/I7H_pv5H3Xl
どちらの場合も
f
変数に
DoFoo
は単なるインターフェイスです。
ではなく
へのポインタです。 しかし
f2
の場合、インターフェース
ホールド
へのポインタが
Foo
構造体を作成します。
インターフェースへのポインターは、ほとんど 決して は有用です。 実際、Goランタイムは数バージョン前に特に変更され、(構造体ポインタの場合のように)インターフェイスポインタを自動的に非参照にしないようになりました。 圧倒的多数の場合、インターフェイスへのポインターは、インターフェイスがどのように機能することになっているのかについての誤解を反映しています。
ただし、インターフェースには制限があります。 インターフェイスに直接構造体を渡すと、その構造体には
値
その型のメソッド(つまり
func (f Foo) Dummy()
ではなく
func (f *Foo) Dummy()
) を使ってインターフェースを満たすことができます。 これは,インターフェイスに元の構造のコピーを保存しているため,ポインタのメソッドは予期せぬ効果をもたらす(つまり,元の構造を変更できない)ためです. したがって、デフォルトの経験則は
構造体へのポインタをインターフェイスに格納する
やむを得ない理由がない限り、そうする必要があります。
具体的には、あなたのコードで、AddFilter関数のシグネチャを変更すると。
func (fp *FilterMap) AddFilter(f FilterInterface) uuid.UUID
そして、GetFilterByIDのシグネチャに。
func (fp *FilterMap) GetFilterByID(i uuid.UUID) FilterInterface
あなたのコードは期待通りに動作します。
fieldfilter
は、タイプ
*FieldFilter
を満たすものである。
FilterInterface
インタフェース型であるため
AddFilter
はそれを受け入れる。
Goのメソッド、型、インターフェースがどのように機能し、互いに統合されているかを理解するための良い参考文献をいくつか紹介します。
関連
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] インターフェースと抽象クラスの違いは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] インターフェースと抽象クラス(一般的なOO)
-
[解決済み] C++でインターフェイスを宣言するには?
-
[解決済み] インターフェースとベースクラス
-
[解決済み] C#のリフレクションで型がインターフェースを実装しているかどうかを判断する方法
-
[解決済み] Typescript によるインターフェース型チェック
-
[解決済み】「インターフェースに合わせたプログラム」とはどういう意味ですか?
-
[解決済み] ファットポインターとは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン