08/04/2022

Structs y algunas notas

Los tipos de datos de toda la vida; enteros, cadenas de texto, booleanos, etc. funcionan muy bien para realizar tareas triviales, pero el desarrollo de software no siempre trata acerca de encontrar el mayor de dos números. Hay muchos problemas que resolver y muchas entidades que modelar.

Una struct es un tipo de datos definido por el usuario que agrupa un conjunto de campos que también tienen tipos definidos.

En efecto, gran parte de la solución de un problema, cuando programamos, pasa por representar de manera adecuada a una entidad del mundo real y a su flujo de vida. Pues bien, ¿De que forma representamos un automóvil y su flujo de fabricación? ¿Como modelamos una factura o un chocolate? y más allá, ¿Como modelamos dos chocolates de distintas marcas?

Cada lenguajes de programación provee su propia forma de lidiar con este problema, la cual se puede resumir en algún tipo de datos personalizado. Algunos ponen a nuestra disposición arreglos asociativos, otros clases, etc. Go por su parte nos deja utilizar structs, los cuales ya mencionabamos en un artículo anterior.

Una struct es un tipo de datos definido por el usuario (en el sentido de que quien programa es el usuario) que agrupa un conjunto de campos que también tienen tipos definidos.

Retomando el ejemplo del automóvil, si lo abstraemos, vemos que posee atributos cómo marca, modelo, año de fabricación, color, etc. Usemos este caso para ejemplificar la declaración de structs

Declaración de structs
  

type Automovil struct {
    Marca string
    Color string
    Ano int
}
  

playground

De esta forma declaramos una struct type conteniendo los campos Marca, Color y Ano cómo una estructura de datos personalizada llamada Automovil.


  
  
package main

import "fmt"

type Automovil struct {
	Marca string
	Color string
        Ano int
}

func(a Automovil) Acelerar() {
    fmt.Println("Este automóvil " + a.Marca + " de color " + a.Color + " esta acelerado")
}

func main() {
	myCar := Automovil{
		Marca: "Suzuki",
		Color: "Rojo",
                Ano: 1999,      // Notese la coma al final de la última línea
	}
          
	fmt.Println("Mi Auto: ", myCar)
 
} 
  

playground

¿Se dio cuenta de cómo definimos una variable de tipo struct Automovil justo al principio de la función Main? Esta forma de inicialización es conocida con el nombre de inicialización por struct literal. También podemos inicializar variables con nuestro struct con el estamento new


  
	var myCar *Automovil
	myCar = new(Automovil)
	myCar.Marca = "Suzuki"
	myCar.Color = "Rojo"
	myCar.Ano = 1999

	fmt.Println("Mi Auto: ", myCar)

  

playground

Asociando métodos a nuestro struct

En Go, las structs puede tener métodos asociados.


  
package main

import "fmt"

type Automovil struct {
	Marca string
	Color string
	Ano   int
}

func (a Automovil) Acelerar() {
	fmt.Println("Este automóvil " + a.Marca + " de color " + a.Color + " esta acelerado")
}

func main() {
	myCar := Automovil{
		Marca: "Suzuki",
		Color: "Rojo",
		Ano:   1999,
	}

	myCar.Acelerar()
}
  


playground

 

Structs, clases y herencia
Go usa la composición para no repetir la implementación de comportamientos, que muy resumidamente, es armar nuestros objetos a partir de otros

Ud podrá pensar; Si un struct tiene campos y también métodos ¿En que se diferencia de una clase? No se equivoque; son parecidos pero no iguales, ambos esconden ideas diferentes en su concepción aunque a nosotros cómo usuarios nos permiten hacer cosas parecidas.

La primera diferencia es que Go no implementa mecanismos de herencia, con esto, surge la segunda diferencia, el encapsulamiento en Go se gestiona a nivel de paquetes, donde un elemento es exportable o no según si su letra inicial es mayúscula o minúscula; con la consecuencia de la no existencia del ámbito protected ¡Porque no existe herencia!

Como no hay herencia, necesitamos una forma para no repetir la implementación de comportamiento. En Go se tomó la decisión de diseño de hacerlo por la vía de la composición, que muy resumidamente es armar nuestros objetos a partir de otros. Si Ud ha trabajado con React o Flutter, entonces este concepto no le será nuevo, pues este patrón forma parte intrínseca de ellos para la creación de componentes.

Un pequeña nota sobre composición sobre herencia

Hay una rica y variada discusión acerca de composición sobre herencia, la cual es muy grande y escapa de las pretenciones de este artículo. Si no ha escuchado sobre el asunto, baste decir que podemos pensar cuando hablamos de composición en una relación del tipo tiene un, esta formado por, mientras que cuando hablamos de herencia, nos referimos a una relación del tipo es un. Fuente: McConnell, Steve (2004). Code Complete: A Practical Handbook of Software Construction. Microsoft Press; 2nd edición.

También puede encontrar una jugosa discusión sobre el tema en este hilo de Stackoverflow.



Composición

Para los diseñadores de Go la decisión de optar por la composición como la forma idiomática de compartir comportamiento y estado es tan importante, que el lenguaje nos permite incrustar en un struct en otro. Ej.


  
package main

import "fmt"

// Automovil el struct base que incrustaremos
type Automovil struct {
	Marca string
	Color string
	Ano   int
}

func (a Automovil) Acelerar() {
	fmt.Println("Este automóvil " + a.Marca + " de color " + a.Color + " esta acelerado")
}

// Delorean Porqué si vas a construir una máquina del tiempo ¿por qué no hacerlo con estilo? Dr. Emmet Lathrop Brawn
type Delorean struct {
	Automovil
}

func (d Delorean) TimeSkip() {
	fmt.Println("Viajando al 5 de noviembre de 1955 ¿Esa es la granja de Peabody?")
}

func NewDelorean() Delorean {
	d := Delorean{}
	d.Marca = "Delorean"
	d.Color = "Plata"
	d.Ano = 1988
	return d
}

func main() {
    myCar := Automovil{
        Marca: "Suzuki",
        Color: "Rojo",
        Ano:   1999,
    }

    myCar.Acelerar()
    
    autoGenial := NewDelorean()
    autoGenial.Acelerar()
    autoGenial.TimeSkip()
}

  


playground

 

Esto nos abre la puerta a sofisticadas formas de modelar las entidades que son parte de nuestro modelo de negocio. Pero eso es conversaciónm para otro artículo.

0 comentarios:

Publicar un comentario