親愛なる仲間の開発者、
私には少し奇妙に思えるこの問題があります。次のコードスニペットをご覧ください。
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
}
ランタイムは上記の行を受け入れません。
「fieldint.AddFilterへの引数でtype * coreinterfaces.FilterInterfaceとしてfieldfilter(type * coreinterfaces.FieldFilter)を使用できません:* 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)
}
すべてが申し分なく、アプリケーションをデバッグするときに実際に含まれているようです
私はこのトピックについて少し混乱しています。このまったく同じ問題を議論している他のブログ投稿とスタックオーバーフロースレッドを見ると(たとえば、- This 、または This )、この例外を発生させる最初のスニペットは動作するはずです。 fieldfilterとfieldmapは、インターフェイスの値ではなく、インターフェイスへのポインタとして初期化されます。 FieldInterfaceを宣言せず、そのインターフェイスに実装を割り当てるために変更する必要がある実際にここで何が起こるかについて頭を包むことができませんでした。これを行うにはエレガントな方法が必要です。
したがって、ここでは2つの概念を混同しています。構造体へのポインタとインターフェイスへのポインタは同じではありません。インターフェイスは、構造体を直接保存することができますまたは構造体へのポインタ。後者の場合、インターフェイスを直接使用するだけで、 not インターフェイスへのポインタです。例えば:
type Fooer interface {
Foo()
}
type Foo struct{}
func (f Foo) Foo() {}
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/BGV9d1-IRW
どちらの場合も、f
のDoFoo
変数は単なるインターフェイスであり、 not インターフェイスへのポインタです。ただし、f2
を格納する場合、インターフェイス holds はFoo
構造体へのポインターを保持します。
インターフェイスへのポインタはほとんど never 便利です。実際、Goランタイムは、いくつかのバージョンに戻り、インターフェイスポインターを自動的に逆参照しないように変更されました(構造体ポインターの場合と同様)。圧倒的多数の場合、インターフェイスへのポインタは、インターフェイスがどのように機能するかについての誤解を反映しています。
ただし、インターフェイスには制限があります。構造体をインターフェースに直接渡す場合、そのタイプの value メソッド(つまりfunc (f Foo) Foo()
ではなくfunc (f *Foo) Foo()
)のみを使用してインターフェースを実現できます。これは、インターフェイスに元の構造のコピーを保存しているため、ポインタメソッドが予期しない効果をもたらす(つまり、元の構造を変更できない)ためです。したがって、デフォルトの経験則では、インターフェースへのポインターを格納します。ただし、やむを得ない理由がない限り。
特にコードで、AddFilter関数のシグネチャを次のように変更した場合:
func (fp *FilterMap) AddFilter(f FilterInterface) uuid.UUID
また、GetFilterByID署名は次のことを行います
func (fp *FilterMap) GetFilterByID(i uuid.UUID) FilterInterface
コードは期待どおりに機能します。 fieldfilter
の型は*FieldFilter
であり、これはFilterInterface
インターフェース型を完全に埋めるので、AddFilter
はそれを受け入れます。
Goでメソッド、タイプ、インターフェースがどのように機能し、相互に統合するかを理解するための優れたリファレンスを次に示します。
GetFilterByID(i uuid.UUID) *FilterInterface
このエラーが表示されるのは、通常、インターフェイスではなくインターフェイスへのポインタを指定しているためです(実際には、インターフェイスを満たす構造体へのポインタになります)。
* interface {...}の有効な使用方法はありますが、より一般的には、「これは、私が書いているコード内のポインタであるインターフェイスです」ではなく、「これはポインタです」と考えています。
受け入れられた答えは、詳細ではありますが、トラブルシューティングに役立たなかったので、ただそこに放り出しました。