Saltar al contenido principal
eLearner.app
Módulo 5 · Lección 3 de 523/50 en el curso~12 min
Lecciones del módulo (3/5)

Composición (embebido)

Ir no tiene herencia. La respuesta idiomática a la reutilización es composición, y en particular incrustación: incluye un tipo dentro de otro sin darle un nombre de campo. Los campos y métodos de el tipo incrustado se promociona y se vuelve directamente accesible como si pertenecían al tipo exterior.

Incrustación de estructuras

Go
type Animal struct {
    Name string
}

func (a Animal) Greet() string {
    return "ciao da " + a.Name
}

type Dog struct {
    Animal        // embedding — NO field name
    Breed string
}

c := Dog{
    Animal: Animal{Name: "Rex"},
    Breed:  "Pastore",
}

fmt.Println(c.Name)         // "Rex" — promoted from Animal
fmt.Println(c.Greet())      // "ciao da Rex" — promoted method
fmt.Println(c.Breed)        // own field

El campo incrustado aún es accesible por el nombre del tipo: c.Animal.Name funciona y es idéntico a c.Name. Es necesario cuando hay colisiones.

Anulación (parcial): método "sombreado"

Si el tipo externo define un método con el mismo nombre que el promovido uno, su método "gana". Desde el interior siempre se puede llegar al incrustado. uno a través del nombre del tipo:

Go
func (c Dog) Greet() string {
    return "BAU! " + c.Animal.Greet()
}

No es herencia polimórfica: es simplemente resolución de nombres léxicos. Para el polimorfismo se utilizan interfaces (Módulo 6).

Incrustación múltiple

Puede incrustar varios tipos:

Go
type Logger struct{ /*...*/ }
func (l Logger) Log(msg string) { /*...*/ }

type Timer struct{ /*...*/ }
func (t Timer) Now() time.Time { /*...*/ }

type Service struct {
    Logger
    Timer
    Name string
}

s := Service{Name: "api"}
s.Log("start")   // promoted from Logger
s.Now()          // promoted from Timer

Si dos tipos incrustados tienen un método con EL MISMO nombre, acceso directo se vuelve ambiguo y el compilador requiere la forma explícita (CÓDIGOPH0 o CÓDIGOPH1).

Incrustación de interfaz

Las interfaces también se pueden "integrar" (ver Módulo 6):

Go
type ReadWriter interface {
    io.Reader
    io.Writer
}

Equivale a la unión de los métodos de Reader y Writer.

Cuándo utilizar composición explícita (no incrustar)

Si desea un campo con nombre y sin promoción automática, use simple composición:

Go
type Dog struct {
    Anim  Animal    // NORMAL field, no promotion
    Breed string
}
c.Anim.Name   // you need the field name

La incrustación es una práctica herramienta de delegación, no una opción de diseño estrictamente mejor que la composición explícita: úsala cuando realmente quieras para promover la API del tipo interno.

Pruébalo

Ejercicio#go.m5.l3.e1
Intentos: 0Cargando...

Defina Perro que incrusta Animal (incrustación, sin nombre de campo) y tiene un campo de cadena Raza.

Cargando editor...
Mostrar pista

Incrustar: escribe el TIPO sin darle un nombre de campo.

Solución disponible después de 3 intentos

Ejercicio#go.m5.l3.e2
Intentos: 0Cargando...

Agregue un método de cadena Greet() a Animal y llámelo directamente en una variable Dog (promoción de método).

Cargando editor...
Mostrar pista

El método definido en Animal se promueve a Perro gracias a la incrustación.

Solución disponible después de 3 intentos

Cuestionario#go.m5.l3.e3
Listo

¿Go admite la herencia clásica?

Go
type B struct { /* extends A? */ }
Opciones de respuesta

Resumen

  • Sin herencia: se compone con incrustación.
  • Incrustar = escribir el TIPO sin un nombre de campo en la estructura.
  • Los campos y métodos del tipo incrustado se promocionan.
  • El acceso explícito siempre está disponible: outer.Inner.Field.
  • Anulación "léxica": el método del tipo externo eclipsa al promovido.
  • Incrustar ≠ is-a: para polimorfismo utilice interfaces.