Drodzy programiści,
Mam ten problem, który wydaje mi się trochę dziwny. Spójrz na ten fragment kodu:
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
}
Na innym pakiecie mam następujący kod:
func DoFilter() {
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}
Środowisko wykonawcze nie zaakceptuje wspomnianej linii, ponieważ
„nie można użyć fieldfilter (type * coreinterfaces.FieldFilter) jako type * coreinterfaces.FilterInterface w argumencie do fieldint.AddFilter: * coreinterfaces.FilterInterface jest wskaźnikiem do interfejsu, a nie interfejsu”
Jednak przy zmianie kodu na:
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)
}
Wszystko jest w porządku, a podczas debugowania aplikacji naprawdę wydaje się, że zawiera
Jestem trochę zdezorientowany w tym temacie. Patrząc na inne posty na blogu i wątki przepełnienia stosu omawiające dokładnie ten sam problem (na przykład - This lub This ), pierwszy fragment kodu, który wywołuje ten wyjątek, powinien działać, ponieważ zarówno fieldfilter, jak i fieldmap są inicjowane jako wskaźniki do interfejsów, a nie wartość interfejsy. Nie byłem w stanie ogarnąć tego, co właściwie się tutaj dzieje, co muszę zmienić, aby nie zadeklarować FieldInterface i przypisać implementacji dla tego interfejsu. Musi być na to elegancki sposób.
* FilterInterface
naFilterInterface
The line_ = filtermap.AddFilter(fieldfilter)
teraz podnosi to: nie można użyć fieldfilter (typ coreinterfaces.FieldFilter) jako typ coreinterfaces.FilterInterface w argumencie do filtermap.AddFilter: coreinterfaces.FieldFilter nie implementuje coreinterfaces.FilterInterface (metoda filtru ma odbiornik wskaźnika) Jednak podczas zmiany linia do_ = filtermap.AddFilter(&fieldfilter)
tego działa. co się tutaj stało? dlaczego?* FilterInterface
na strukturę, która implementuje ten interfejs, łamie ideę przekazywania interfejsów do funkcji. To, co chciałem osiągnąć, to nie bycie związanym z tą strukturą, którą mijałem, ale raczej każdą strukturą, która implementuje interfejs, którego chcę użyć. Jakieś zmiany w kodzie, które uważasz za bardziej wydajne lub zgodne ze standardami, które powinienem wykonać? Z przyjemnością skorzystam z usług przeglądu kodu :)Odpowiedzi:
Więc mylisz tutaj dwie koncepcje. Wskaźnik do struktury i wskaźnik do interfejsu to nie to samo. Interfejs może przechowywać bezpośrednio strukturę lub wskaźnik do struktury. W tym drugim przypadku nadal używasz interfejsu bezpośrednio, a nie wskaźnika do interfejsu. Na przykład:
Wynik:
https://play.golang.org/p/I7H_pv5H3Xl
W obu przypadkach
f
zmienna inDoFoo
jest tylko interfejsem, a nie wskaźnikiem do interfejsu. Jednak podczas przechowywaniaf2
interfejs zawiera wskaźnik doFoo
struktury.Wskaźniki do interfejsów prawie nigdy nie są przydatne. W rzeczywistości środowisko uruchomieniowe Go zostało specjalnie zmienione kilka wersji z powrotem, aby nie były już automatycznie wyłuskiwane wskaźniki interfejsu (tak jak w przypadku wskaźników struktury), aby zniechęcić do ich używania. W przeważającej większości przypadków wskaźnik do interfejsu odzwierciedla niezrozumienie tego, jak powinny działać interfejsy.
Istnieje jednak ograniczenie dotyczące interfejsów. Jeśli przekażesz strukturę bezpośrednio do interfejsu, tylko metody wartości tego typu (tj.
func (f Foo) Dummy()
Niefunc (f *Foo) Dummy()
) mogą być używane do wypełnienia interfejsu. Dzieje się tak, ponieważ przechowujesz kopię oryginalnej struktury w interfejsie, więc metody wskaźnikowe miałyby nieoczekiwane efekty (tj. Nie byłyby w stanie zmienić oryginalnej struktury). Dlatego domyślną zasadą jest przechowywanie wskaźników do struktur w interfejsach , chyba że istnieje ważny powód, aby tego nie robić.W szczególności za pomocą kodu, jeśli zmienisz podpis funkcji AddFilter na:
Oraz podpis GetFilterByID do:
Twój kod będzie działał zgodnie z oczekiwaniami.
fieldfilter
jest typu*FieldFilter
, który wypełniaFilterInterface
typ interfejsu, a tym samymAddFilter
go zaakceptuje.Oto kilka dobrych odniesień do zrozumienia, jak metody, typy i interfejsy działają i integrują się ze sobą w Go:
źródło
Kiedy otrzymuję ten błąd, zwykle dzieje się tak, ponieważ określam wskaźnik do interfejsu zamiast interfejsu (który w rzeczywistości będzie wskaźnikiem do mojej struktury, która spełnia interfejs).
* Interfejs {...} ma poprawne zastosowanie, ale częściej myślę po prostu „to jest wskaźnik” zamiast „to jest interfejs, który jest wskaźnikiem w kodzie, który piszę”
Po prostu wyrzucenie go tam, ponieważ zaakceptowana odpowiedź, choć szczegółowa, nie pomogła mi w rozwiązaniu problemu.
źródło