Embedding en Go: integrando estructuras en estructuras
Esta semana continuando con el reto de #100DaysOfCode me encontré con otra capacidad que tiene Go para facilitar el uso de las estructuras de datos mediante un método llamado struct embedding
.
Campos de datos
En Go, al igual que en muchos otros lenguajes de programación, es posible definir estructuras que contienen campos que refieren a otras estructuras. Esto se conoce como composición, un principio que proviene de la programación orientada a objetos.
Por ejemplo si estamos construyendo una herramienta para trabajar con figuras geométricas uno de los conceptos fundamentales es el de un punto en el plano cartesiano. En Go se realiza de la siguiente manera:
type Point struct {
X, Y float64
}
Si deseamos a partir de esto crear un punto con color podemos realizarlo de la siguiente manera:
type ColoredPoint struct {
Point,
Color string,
}
Hay un detalle muy importante a observar: no tuvimos que definir un campo nominal al añadir la estructura Point
, sino que integramos la estructuraPoint
en ColoredPoint
.
Al integrar una estructura en Go se obtiene la capacidad de soportar una promoción de las funciones en la nueva estructura. Por ejemplo
func main() {
var bluePoint ColoredPoint
bluePoint.Color = "blue"
bluePoint.X = 10
bluePoint.Y = 1.23
}
// imprime
Punto azul ColoredPoint blue Point {10.00, 1.23}
Al definir la variable bluePoint
del tipo ColoredPoint
podemos acceder a los campos X
y Y
directamente como si se tratasen de propiedades que fueron originalmente definidas en dicha estructura si así lo deseamos.
En este caso podemos también inicializar una variable del tipo ColoredPoint
sin nombrar los campos ya que el compilador los infiere por nosotros:
func main() {
redPoint := geometry.ColoredPoint{ geometry.Point{1, 1}, "red" }
fmt.Println("Punto rojo", redPoint)
}
// imprime
Punto rojo ColoredPoint red Point {1.00, 1.00}
Métodos
La integración permite también utilizar los métodos asociados con la estructura integrada.
Por ejemplo para Point
se ha definido una función que calcula la distancia con otro Point
de la siguiente manera:
func (p Point) Distance(q Point) float64 {
return math.Sqrt(math.Pow((q.X - p.X), 2) + math.Pow((q.Y - p.Y), 2))
}
Este método puede ser usado por ColoredPoint
de forma directa
func main() {
redPoint := ColoredPoint{ Point{1, 1}, "red" }
bluePoint := ColoredPoint{ Point{10, 1.23}, "blue" }
dRedBlue := redPoint.Distance(bluePoint)
fmt.Println("Distancia de rojo a azul", dRedBlue)
}
// imprime
Distancia de rojo a azul 9.002
Integrar estructuras en Go permite que la composición sea más simple y legible facilitando su uso como clientes.
Pueden encontrar el código en este repositorio.