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
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 fieldEl 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:
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:
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 TimerSi 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):
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:
type Dog struct {
Anim Animal // NORMAL field, no promotion
Breed string
}
c.Anim.Name // you need the field nameLa 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
Defina Perro que incrusta Animal (incrustación, sin nombre de campo) y tiene un campo de cadena Raza.
Mostrar pista
Incrustar: escribe el TIPO sin darle un nombre de campo.
Solución disponible después de 3 intentos
Agregue un método de cadena Greet() a Animal y llámelo directamente en una variable Dog (promoción de método).
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
¿Go admite la herencia clásica?
type B struct { /* extends A? */ }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.