Quería ampliar la respuesta dada por @jimt aquí . Esa respuesta es correcta y me ayudó enormemente a resolver esto. Sin embargo, hay algunas advertencias a ambos métodos (alias, incrustar) con las que tuve problemas.
nota : uso los términos padre e hijo, aunque no estoy seguro de que sea el mejor para la composición. Básicamente, padre es el tipo que desea modificar localmente. Hijo es el nuevo tipo que intenta implementar esa modificación.
Método 1 - Definición de tipo
type child parent
// or
type MyThing imported.Thing
- Proporciona acceso a los campos.
- No proporciona acceso a los métodos.
type child struct {
parent
}
// or with import and pointer
type MyThing struct {
*imported.Thing
}
- Proporciona acceso a los campos.
- Proporciona acceso a los métodos.
- Requiere consideración para la inicialización.
Resumen
- Usando el método de composición, el padre incrustado no se inicializará si es un puntero. El padre debe inicializarse por separado.
- Si el padre incrustado es un puntero y no se inicializa cuando se inicializa el niño, se producirá un error de desreferencia de puntero nulo.
- Tanto la definición de tipo como los casos de inserción proporcionan acceso a los campos del padre.
- La definición de tipo no permite el acceso a los métodos del padre, pero la incorporación del padre sí.
Puedes ver esto en el siguiente código.
ejemplo de trabajo en el patio de recreo
package main
import (
"fmt"
)
type parent struct {
attr string
}
type childAlias parent
type childObjParent struct {
parent
}
type childPointerParent struct {
*parent
}
func (p *parent) parentDo(s string) { fmt.Println(s) }
func (c *childAlias) childAliasDo(s string) { fmt.Println(s) }
func (c *childObjParent) childObjParentDo(s string) { fmt.Println(s) }
func (c *childPointerParent) childPointerParentDo(s string) { fmt.Println(s) }
func main() {
p := &parent{"pAttr"}
c1 := &childAlias{"cAliasAttr"}
c2 := &childObjParent{}
// When the parent is a pointer it must be initialized.
// Otherwise, we get a nil pointer error when trying to set the attr.
c3 := &childPointerParent{}
c4 := &childPointerParent{&parent{}}
c2.attr = "cObjParentAttr"
// c3.attr = "cPointerParentAttr" // NOGO nil pointer dereference
c4.attr = "cPointerParentAttr"
// CAN do because we inherit parent's fields
fmt.Println(p.attr)
fmt.Println(c1.attr)
fmt.Println(c2.attr)
fmt.Println(c4.attr)
p.parentDo("called parentDo on parent")
c1.childAliasDo("called childAliasDo on ChildAlias")
c2.childObjParentDo("called childObjParentDo on ChildObjParent")
c3.childPointerParentDo("called childPointerParentDo on ChildPointerParent")
c4.childPointerParentDo("called childPointerParentDo on ChildPointerParent")
// CANNOT do because we don't inherit parent's methods
// c1.parentDo("called parentDo on childAlias") // NOGO c1.parentDo undefined
// CAN do because we inherit the parent's methods
c2.parentDo("called parentDo on childObjParent")
c3.parentDo("called parentDo on childPointerParent")
c4.parentDo("called parentDo on childPointerParent")
}
“extension methods are not object-oriented”
) para C #, pero al mirarlos hoy, inmediatamente me acordé de las interfaces de Go (y su enfoque para repensar la orientación a objetos), y luego tuve esta misma pregunta.