miércoles, 24 de octubre de 2018

Tipos definidos en Go: estructuras

Llegó el momento de pasar a la definición de tipos definidos compuestos, los cuales permitirán componer un tipo de dato compuesto de varios tipos básicos, a modo de registro o de ficha de datos. Go facilita la definición y operación de tipos compuestos mediante estructuras.

Declaración de una estructura

Para definir una estructura, hemos de declarar un tipo definido mediante la palabra clave type, seguido del nombre que designemos para la estructura y de la palabra clave struct. Después, hemos de declarar cada uno de los campos de la estructura y su tipo, como si declarásemos variables básicas.

En el siguiente ejemplo, definiremos una estructura llamada Empleado, la cual contendrá los campos nombre, teléfono y esCasado.

type Empleado struct {
   nombre, telefono string
   esCasado bool
}

Una estructura es un tipo definido y no se utiliza directamente, si no que hemos de declarar variables de ese tipo, y utilizar dichas variables para leer y escribir los valores correspondientes. La estructura es como un molde que define la forma que tendrá los objetos que salgan de dicho molde. Estos objetos se denominan instancias.

Creación de instancias

Una instancia es un objeto creado a partir de una estructura. Básicamente, es una variable declarada del tipo de la estructura.

Existen varios métodos de crear y utilizar una instancia. A continuación se explica cada una de ellas.

Declaración simple

La instancia (o variable) se declara en primer lugar. Después se accede, individualmente, a cada uno los campos o propiedades de la estructura.

var empleado1 Empleado
empleado1.nombre = "Rafael Hernampérez"
empleado1.telefono = "687990033"
empleado1.esCasado = true

Para acceder a un campo (ya sea para asignar un valor como para leer su valor), se especifica el nombre de la instancia (variable), seguido de un punto y del nombre del campo o propiedad.

En este aspecto, las estructuras en Go son muy similares a la programación orientada a objetos en otros lenguajes de programación. El concepto aquí, es el uso de estas estructuras como contenedores de datos compuestos.

Declaración y asignación en un paso

En el siguiente ejemplo, se asignan los datos a una estructura en la misma declaración. Para ello, dicha declaración debe realizarse por inferencia, y los valores se pasan como un objeto JSON, al cual hay que anteponer el nombre de la estructura para forzar el casting.

empleado2 := Empleado{
   nombre:   "Eduardo Fernández",
   telefono: "677890911",
   esCasado: false,
}
Notas
  • El casting es un concepto que veremos más adelante en este tutorial. El casting obliga a que el dato o valor sea del tipo especificado. Suele utilizarse para convertir valores entre diferentes tipos, si son compatibles. En este caso, obliga a que los datos tengan la misma estructura que la declarada para la estructura Empleados. Si no es así, se producirá un error.
  • Cuando escribimos este tipo de sintaxis, tras el último valor ha de especificarse el cierre de las llaves (}), o bien terminar con una coma (como ha sido este caso). Si no se hace así, el compilador de Go da un error: syntax error: unexpected newline, expecting comma or }

Declaración y asignación mediante un puntero

Un puntero es un concepto avanzado que veremos en otro capítulo de este tutorial. Como avance, diremos que los datos son gestionados directamente en la memoria. El puntero apunta a la dirección de la memoria de una variable o instancia. Después, mediante la indirección de memoria, el puntero apuntará o referenciará a la dirección de memoria de un objeto JSON con los datos.

empleado3 := new(Empleado)
empleado3 = &Empleado{
   nombre:   "Sara Connor",
   telefono: "620990134",
   esCasado: false,
}

Estructuras anónimas

Una estructura anónima es creada y utilizada una única vez, en el mismo momento de declarar la instancia que la utiliza.

rectangulo := struct {
   alto, ancho float64
}{
   alto:  12.5,
   ancho: 20.8}

Este tipo de estructuras son útiles en casos de un sólo uso, ahorrando tener declaraciones que no se utilizan.

Ejemplo

El siguiente programa repasa todos los conceptos vistos en este capítulo.

package main

import "fmt"

func main() {

   // Definicion de la estructura Empleado
   type Empleado struct {
      nombre, telefono string
      esCasado         bool
   }

   // Metodo 1: declaracion y posterior asignacion
   var empleado1 Empleado
   empleado1.nombre = "Rafael Hernampérez"
   empleado1.telefono = "687990033"
   empleado1.esCasado = true

   // Metodo 2: declaracion y asignacion al mismo tiempo
   empleado2 := Empleado{
      nombre:   "Eduardo Fernández",
      telefono: "677890911",
      esCasado: false,
   }

   // Metodo 3: declaracion de un puntero al tipo
   // La asignacion posterior se realiza con indireccion
   empleado3 := new(Empleado)
   empleado3 = &Empleado{
      nombre:   "Sara Connor",
      telefono: "620990134",
      esCasado: false,
   }

   fmt.Printf("Empleado 1: %v (%T)\n",
      empleado1, empleado1)

   fmt.Printf("Empleado 2: %v (%T)\n",
      empleado2, empleado2)

   fmt.Printf("Empleado 3: %v (%T)\n",
      empleado3, empleado3)

   // Estructura anonima
   rectangulo := struct {
      alto, ancho float64
   }{alto:  12.5, ancho: 20.8 }

   fmt.Printf("rectangulo: %v (%T)\n", rectangulo, rectangulo)
}

El resultado es el siguiente:

$ go estructura-datos.go
Empleado 1: {Rafael Hernampérez 687990033 true} (main.Empleado)
Empleado 2: {Eduardo Fernández 677890911 false} (main.Empleado)
Empleado 3: &{Sara Connor 620990134 false} (*main.Empleado)
rectangulo: {12.5 20.8} (struct { alto float64; ancho float64 })

Enlaces de interés

No hay comentarios:

Publicar un comentario