miércoles, 2 de octubre de 2019

Anonymous fields en Go


Continuamos con en go

Como podemos aplicar composiciones a un lenguaje no orientado a objeto y que no se vea forzado? Y la respuesta la tiene Go con Anonymous fields. En Go solo tenemos estructuras y funciones que trabajan con dichas estructuras. Si bien Go tiene una forma de escribir estas estructuras y su interacción con las funciones que hace imaginar a objetos, esto no es así. 

Pero Go utiliza composiciones, como lo hace? componiendo estructuras:  Go permite definir una estructura que tiene campos pero sin nombres de variables. Estos campos se llaman campos anónimos. Hagamos algunos ejemplos para descubrir cuáles son y cómo serán útiles.

En el siguiente ejemplo, hemos definido una estructura de Cocina, que solo contiene el número de platos como un campo. Definimos otro campo llamado House, que contiene una instancia de Kitchen como campo, pero es un campo anónimo, porque no le hemos dado un nombre de variable.

Los campos anónimos en las estructuras Go nos permiten atajar la notación de puntos, así como también nos permiten usar composiciones para agregar métodos a un tipo. Veamos un ejemplo : 

type A struct {
    X int
    Y int
}
 
type B struct {
    Z int
}
 
type C struct {
    AValue A
    BValue B
}

La estructura C contiene a la estructura A, por lo tanto la estructura C esta compuesta. Y podemos llamar a campos de C por medio de los campos descriptos en A o B : 

 c := C {}
c.AValue.X = 1

Podemos pasar a C de modo anónimo por lo tanto queda así : 

type C struct {
    A
    B
}

nos permite reducir el uso de la notación de puntos y acceder a X en A como si fuera un campo dentro de la estructura C en sí, es decir

c := C {}
c.X = 1

De acuerdo, pero ¿qué pasaría si B struct ahora reemplazara el nombre del campo Z con X?

type A struct {
    X int
    Y int
}
 
type B struct {
    X int
}

Ahora tenemos una situación en la que tanto A como B tienen el mismo nombre de campo, bueno, aún podemos usar campos anónimos, pero volvemos a usar más notación de puntos nuevamente para evitar el conflicto obvio de nombre de campo, es decir:

c := C {}
c.A.X = 1
c.B.X = 2

Los inicializadores no admiten accesos directos, es decir : 

c := C{ A : A{2, 4}, B : B { 12 }}
// or
c := C{ A : A{X : 2, Y : 4}, B : B { Z: 12 }}
 
Más poderoso que el azúcar sináptico de los campos anónimos, es que también podemos usar la composición para aumentar los métodos disponibles en la estructura C. Por ejemplo, ahora agreguemos un método al tipo A que nos permite mover nuestro punto X, Y

func (a *A) Move(amount int) {
    a.X += amount
    a.Y += amount
}

Ahora podemos llamar al método con C :

c.Move(10)

También podemos crear más métodos a través de un patrón de composición en el tipo C si queremos usar tipos vacíos, supongamos que tenemos el tipo D y amplia la composición del tipo C, bueno podemos : 

type D struct {}
 
type C struct {
    A
    B
    D
}

ahora podemos agregar métodos a D y, por supuesto, estarán disponibles como parte de C. Entonces, por ejemplo, tal vez D actúa como un receptor para los métodos que serializan datos a JSON, ahora nuestro tipo C también parecerá tener esos métodos.



No hay comentarios.:

Publicar un comentario