Estimados compañeros desarrolladores,
Tengo este problema que me parece un poco extraño. Eche un vistazo a este fragmento de código:
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
}
En algún otro paquete, tengo el siguiente código:
func DoFilter() {
fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
filtermap := &coreinterfaces.FilterMap{}
_ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}
El tiempo de ejecución no aceptará la línea mencionada porque
"no se puede usar fieldfilter (tipo * coreinterfaces.FieldFilter) como tipo * coreinterfaces.FilterInterface en el argumento de fieldint.AddFilter: * coreinterfaces.FilterInterface es un puntero a la interfaz, no a la interfaz"
Sin embargo, al cambiar el código a:
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)
}
Todo está bien y al depurar la aplicación realmente parece incluir
Estoy un poco confundido sobre este tema. Al mirar otras publicaciones de blog y los subprocesos de desbordamiento de pila que discuten exactamente este mismo problema (por ejemplo, esto o esto ), el primer fragmento que genera esta excepción debería funcionar, porque tanto el filtro de campo como el mapa de campo se inicializan como punteros a interfaces, en lugar del valor de interfaces. No he podido entender lo que realmente sucede aquí que necesito cambiar para no declarar una FieldInterface y asignar la implementación para esa interfaz. Debe haber una forma elegante de hacer esto.
* FilterInterface
aFilterInterface
La línea_ = filtermap.AddFilter(fieldfilter)
ahora surge esto: no se puede usar fieldfilter (tipo coreinterfaces.FieldFilter) como tipo coreinterfaces.FilterInterface en argumento para filtermap.AddFilter: coreinterfaces.FieldFilter no implementa coreinterfaces.FilterInterface (El método de filtro tiene puntero receptor) Sin embargo, al cambiar el línea a_ = filtermap.AddFilter(&fieldfilter)
que funciona. ¿Qué pasa aquí? ¿porqué es eso?* FilterInterface
a una estructura que implementa esta interfaz, se rompe la idea de pasar interfaces a funciones. Lo que quería lograr no es estar vinculado a la estructura que estaba pasando, sino a cualquier estructura que implemente la interfaz que me interesa usar. ¿Algún cambio de código que pueda pensar que es más eficiente o que cumple con los estándares para mí? Estaré encantado de utilizar algunos servicios de revisión de código :)Respuestas:
Entonces estás confundiendo dos conceptos aquí. Un puntero a una estructura y un puntero a una interfaz no son lo mismo. Una interfaz puede almacenar una estructura directamente o un puntero a una estructura. En el último caso, todavía usa la interfaz directamente, no un puntero a la interfaz. Por ejemplo:
Salida:
https://play.golang.org/p/I7H_pv5H3Xl
En ambos casos, la
f
variable inDoFoo
es solo una interfaz, no un puntero a una interfaz. Sin embargo, al almacenarf2
, la interfaz tiene un puntero a unaFoo
estructura.Los punteros a las interfaces casi nunca son útiles. De hecho, el tiempo de ejecución de Go se cambió específicamente en algunas versiones para que ya no desreferenciaran automáticamente los punteros de interfaz (como lo hace con los punteros de estructura), para desalentar su uso. En la inmensa mayoría de los casos, un puntero a una interfaz refleja un malentendido de cómo se supone que funcionan las interfaces.
Sin embargo, existe una limitación en las interfaces. Si pasa una estructura directamente a una interfaz, solo se pueden usar métodos de valor de ese tipo (es decir
func (f Foo) Dummy()
, nofunc (f *Foo) Dummy()
) para completar la interfaz. Esto se debe a que está almacenando una copia de la estructura original en la interfaz, por lo que los métodos de puntero tendrían efectos inesperados (es decir, no pueden alterar la estructura original). Por lo tanto, la regla general predeterminada es almacenar punteros a estructuras en interfaces , a menos que haya una razón convincente para no hacerlo.Específicamente con su código, si cambia la firma de la función AddFilter a:
Y la firma GetFilterByID para:
Tu código funcionará como se esperaba.
fieldfilter
es de tipo*FieldFilter
, que completa elFilterInterface
tipo de interfaz y, porAddFilter
lo tanto, lo aceptará.Aquí hay un par de buenas referencias para comprender cómo los métodos, tipos e interfaces funcionan y se integran entre sí en Go:
fuente
Cuando recibo este error, generalmente es porque estoy especificando un puntero a una interfaz en lugar de una interfaz (que en realidad será un puntero a mi estructura que cumple con la interfaz).
Hay un uso válido para * interface {...} pero lo más común es que pienso 'esto es un puntero' en lugar de 'esta es una interfaz que resulta ser un puntero en el código que estoy escribiendo'
Simplemente tirándolo porque la respuesta aceptada, aunque detallada, no me ayudó a solucionar el problema.
fuente