Уважаемые коллеги-разработчики!
У меня возникла эта проблема, которая мне кажется немного странной. Взгляните на этот фрагмент кода:
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 (тип * coreinterfaces.FieldFilter) как тип * coreinterfaces.FilterInterface в аргументе fieldint.AddFilter: * 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 и не назначал реализацию для этого интерфейса. Должен быть изящный способ сделать это.
* FilterInterface
наFilterInterface
Строка_ = filtermap.AddFilter(fieldfilter)
теперь вызывает следующее: нельзя использовать fieldfilter (тип coreinterfaces.FieldFilter) в качестве типа coreinterfaces.FilterInterface в аргументе filtermap.AddFilter: coreinterfaces.FieldFilter не реализует coreinterfaces.FilterInterface (метод фильтра имеет приемник указателя) Однако при изменении строка к_ = filtermap.AddFilter(&fieldfilter)
нему работает. Что здесь происходит? это почему?* FilterInterface
на структуру, реализующую этот интерфейс, нарушает идею передачи интерфейсов функциям. Я хотел не быть привязанным к той структуре, которую я передавал, а скорее к любой структуре, которая реализует интерфейс, который мне интересно использовать. Какие-либо изменения кода, которые вы считаете более эффективными или отвечающими стандартам, для меня? Я буду рад воспользоваться услугами проверки кода :)Ответы:
Итак, вы путаете здесь два понятия. Указатель на структуру и указатель на интерфейс - это не одно и то же. Интерфейс может хранить либо структуру напрямую, либо указатель на структуру. В последнем случае вы по-прежнему просто используете интерфейс напрямую, а не указатель на интерфейс. Например:
Вывод:
https://play.golang.org/p/I7H_pv5H3Xl
В обоих случаях
f
переменная inDoFoo
- это просто интерфейс, а не указатель на интерфейс. Однако при сохраненииf2
интерфейс содержит указатель наFoo
структуру.Указатели на интерфейсы почти никогда не используются. Фактически, среда выполнения Go была специально изменена в нескольких версиях, чтобы больше не было автоматического разыменования указателей интерфейсов (как это происходит с указателями структур), чтобы препятствовать их использованию. В подавляющем большинстве случаев указатель на интерфейс отражает неправильное понимание того, как интерфейсы должны работать.
Однако существует ограничение на интерфейсы. Если вы передаете структуру непосредственно в интерфейс, только методы значения этого типа (т. Е.
func (f Foo) Dummy()
Неfunc (f *Foo) Dummy()
) могут использоваться для выполнения интерфейса. Это связано с тем, что вы храните копию исходной структуры в интерфейсе, поэтому методы указателя будут иметь неожиданные эффекты (т. Е. Не могут изменить исходную структуру). Таким образом, практическое правило по умолчанию - хранить указатели на структуры в интерфейсах , если нет веской причины не делать этого.В частности, с вашим кодом, если вы измените подпись функции AddFilter на:
И подпись GetFilterByID для:
Ваш код будет работать должным образом.
fieldfilter
имеет тип*FieldFilter
, который заполняетFilterInterface
тип интерфейса и, таким образомAddFilter
, принимает его.Вот пара хороших ссылок для понимания того, как методы, типы и интерфейсы работают и интегрируются друг с другом в Go:
источник
Когда я получаю эту ошибку, обычно это происходит потому, что я указываю указатель на интерфейс вместо интерфейса (который на самом деле будет указателем на мою структуру, которая выполняет интерфейс).
Есть допустимое использование для * interface {...}, но чаще я просто думаю «это указатель» вместо «это интерфейс, который оказывается указателем в коде, который я пишу»
Просто выбросил его, потому что принятый ответ, хотя и подробный, не помог мне в устранении неполадок.
источник