struct go embedding

¿Puede el método de estructura incrustado tener conocimiento de padre/hijo?



go embedding (2)

He estado trabajando con Go on and off en mi tiempo libre durante unos meses y siento que me he acostumbrado. Al provenir de los lenguajes tradicionales de OOP, como Java y PHP, me costó mucho comprender la composición e incrustarla en Go. Creo que finalmente hizo clic recientemente y quiero usarlo más, pero he encontrado un obstáculo para una idea que tengo.

Digamos que tengo una estructura de un paquete que tiene un método Validate y lo incorporé en mi estructura en el paquete en el que estoy trabajando actualmente. ¿Hay alguna manera (que posea ambos paquetes) de que pueda obtener una referencia a la estructura que Qué está haciendo la incrustación dentro del método Validar? Algo así como una forma de ver quién me llamó, ya que lo llamaría al "padre" en lugar del incrustado.

Trataré de visualizar esto ...

type B struct {} func (b B) Validate() { // get reference somehow of A obj } type A struct { B } a := A{B{}} a.Validate()

Siento que esto no es posible, pero sería genial si pudieras. Me imagino que necesitarías hacer que A y B sean del mismo tipo de interfaz para que esto funcione. Cualquier pensamiento o ayuda será muy apreciada.


Cualquier tipo de referencia de los parent es imposible. ¿Qué esperarías hacer con los padres? Dado que serían tipos potencialmente muy diferentes, serían incompatibles para hacer algo significativo.

Si necesita algo en común entre los diferentes tipos, desea una interfaz y deberá pasarla:

type B struct {} func (b B) Validate(parent MyInterface) { } type A struct { B } // A implements MyInterface a := A{B{}} a.Validate(a)

Si puede explicar lo que realmente está tratando de lograr, es casi seguro que haya una mejor manera que esta.


Esto es algo que no es posible. Para comprender mejor por qué, vea esta versión ligeramente modificada de su ejemplo:

type B struct{} func (b *B) Validate() { fmt.Printf("b:%p/n", b) } type A struct { *B } func main() { b := B{} a1 := A{&b} a2 := A{&b} a1.Validate() a2.Validate() a1.B.Validate() a2.B.Validate() b.Validate() }

Salida como se esperaba, el mismo valor de *B todas partes ( Go Playground ):

b: 0x1becd8 b: 0x1becd8 b: 0x1becd8 b: 0x1becd8 b: 0x1becd8

Como puede ver, cambié el receptor del método y el tipo incrustado al puntero de B

De este ejemplo está claro: ¡puede usar el mismo valor de B (o más bien la misma dirección de un valor de B ) para incrustar en diferentes valores de tipo A !

Y puede llamar a Validate() en ambos: entonces el "padre" teórico ni siquiera es "constante" para un valor dado de *B Esto no sería un B.Validate() , pero: teniendo un valor de A , puede llamar al método promocionado B.Validate() escribiendo a.Validate() cual está bien, pero también puede llamarlo como aBValidate() - ahora esta vez no tienes realmente un valor de A (discutible, pero Validate() se llama con un valor de *B y no A ), pero finalmente también puedes llamar a b.Validate() - esta vez definitivamente no tiene un valor de A

No hay un tipo definido para el padre, B (o *B ) se puede incrustar en cualquier tipo (por lo que no podría ser otra cosa que la interface{} ).

Entonces, imagen: tiene un valor concreto de *B y cuando se llama a su método Validate() , a veces hay un padre, y otras no. Entonces, ¿cuál sería la justificación para tener un padre?

Volviendo a su ejemplo: para que este método Validate() valide algo significativo, debe (debe) pasarse al método Validate() como un parámetro, de forma explícita y no automática.

Lo mejor que puedes hacer es lo que captncraig escribió en su respuesta (+1).

Sin embargo, puede simplificarlo un poco si agrega explícitamente un método a A que llamaría B.Validate() esta manera:

func (a *A) Validate2() { a.Validate(a) } // And using it: a.Validate2()

No hay justificación para un validador del tipo que imaginas que está incrustado en A , debería ser solo un campo de A , o como no hay una relación directa, puede ser un validador "independiente". En ambos casos, puede agregar un método auxiliar Validate() a A si desea simplificar la validación.