Rekan pengembang yang terhormat,
Saya punya masalah ini yang tampaknya agak aneh bagi saya. Lihat cuplikan kode ini:
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
}
Di beberapa paket lain, saya memiliki kode berikut:
func DoFilter() {
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}
Waktu proses tidak akan menerima baris yang disebutkan karena
"tidak dapat menggunakan fieldfilter (ketik * coreinterfaces.FieldFilter) sebagai jenis * coreinterfaces.FilterInterface dalam argumen ke fieldint.AddFilter: * coreinterfaces.FilterInterface adalah penunjuk ke antarmuka, bukan antarmuka"
Namun, saat mengubah kode menjadi:
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)
}
Semuanya baik-baik saja dan saat men-debug aplikasi itu sepertinya benar-benar disertakan
Saya agak bingung dengan topik ini. Saat melihat posting blog lain dan utas stack overflow yang membahas masalah yang sama persis (misalnya - Ini , atau Ini ), potongan pertama yang memunculkan pengecualian ini seharusnya berfungsi, karena fieldfilter dan fieldmap diinisialisasi sebagai penunjuk ke antarmuka, bukan nilai antarmuka. Saya belum bisa memahami apa yang sebenarnya terjadi di sini yang perlu saya ubah agar saya tidak mendeklarasikan FieldInterface dan menetapkan implementasi untuk antarmuka itu. Harus ada cara yang elegan untuk melakukan ini.
* FilterInterface
keFilterInterface
The line_ = filtermap.AddFilter(fieldfilter)
now memunculkan ini: tidak dapat menggunakan fieldfilter (ketik coreinterfaces.FieldFilter) sebagai tipe coreinterfaces.FilterInterface dalam argumen ke filtermap.AddFilter: coreinterfaces.FieldFilter tidak mengimplementasikan coreinterfaces.FilterInterface (metode Filter memiliki penerima pointer) Namun ketika mengubah baris untuk_ = filtermap.AddFilter(&fieldfilter)
bekerja. Apa yang terjadi di sini? mengapa demikian?* FilterInterface
menjadi struct yang mengimplementasikan antarmuka ini, ini mematahkan gagasan untuk meneruskan antarmuka ke fungsi. Apa yang ingin saya capai bukanlah terikat pada struktur apa yang saya lewati, melainkan apa saja struct yang mengimplementasikan antarmuka yang ingin saya gunakan. Adakah perubahan kode yang menurut Anda lebih efisien atau sesuai standar yang harus saya lakukan? Saya akan dengan senang hati menggunakan beberapa layanan peninjauan kode :)Jawaban:
Jadi Anda membingungkan dua konsep di sini. Sebuah pointer ke sebuah struct dan sebuah pointer ke sebuah antarmuka tidak sama. Antarmuka dapat menyimpan baik struct secara langsung atau penunjuk ke struct. Dalam kasus terakhir, Anda masih menggunakan antarmuka secara langsung, bukan penunjuk ke antarmuka. Sebagai contoh:
Keluaran:
https://play.golang.org/p/I7H_pv5H3Xl
Dalam kedua kasus,
f
variabel dalamDoFoo
hanyalah sebuah antarmuka, bukan sebuah penunjuk ke sebuah antarmuka. Namun, saat menyimpanf2
, antarmuka menahan penunjuk ke fileFoo
struktur.Pointer ke antarmuka hampir tidak pernah ada berguna. Nyatanya, Go runtime secara khusus diubah beberapa versi kembali menjadi tidak lagi secara otomatis penunjuk antarmuka dereferensi (seperti yang dilakukannya untuk penunjuk struktur), untuk mencegah penggunaannya. Dalam sebagian besar kasus, penunjuk ke antarmuka mencerminkan kesalahpahaman tentang bagaimana antarmuka seharusnya bekerja.
Namun, ada batasan pada antarmuka. Jika Anda mengirimkan struktur secara langsung ke antarmuka, hanya metode nilai dari jenis itu (mis.
func (f Foo) Dummy()
, Bukanfunc (f *Foo) Dummy()
) yang dapat digunakan untuk memenuhi antarmuka. Ini karena Anda menyimpan salinan dari struktur asli di antarmuka, jadi metode penunjuk akan memiliki efek yang tidak diharapkan (mis. Tidak dapat mengubah struktur asli). Jadi, aturan umum default adalah menyimpan pointer ke struktur di antarmuka , kecuali ada alasan kuat untuk tidak melakukannya.Khususnya dengan kode Anda, jika Anda mengubah tanda tangan fungsi AddFilter menjadi:
Dan tanda tangan GetFilterByID untuk:
Kode Anda akan berfungsi seperti yang diharapkan.
fieldfilter
adalah tipe*FieldFilter
, yang memenuhiFilterInterface
tipe antarmuka, dan dengan demikianAddFilter
akan menerimanya.Berikut beberapa referensi yang bagus untuk memahami bagaimana metode, tipe, dan antarmuka bekerja dan terintegrasi satu sama lain di Go:
sumber
Ketika saya mendapatkan kesalahan ini, biasanya karena saya menentukan penunjuk ke antarmuka daripada antarmuka (yang sebenarnya akan menjadi penunjuk ke struct saya yang memenuhi antarmuka).
Ada penggunaan yang valid untuk * antarmuka {...} tetapi lebih umum saya hanya berpikir 'ini adalah penunjuk' daripada 'ini adalah antarmuka yang kebetulan menjadi penunjuk dalam kode yang saya tulis'
Hanya membuangnya ke sana karena jawaban yang diterima, meskipun terperinci, tidak membantu saya memecahkan masalah.
sumber