jueves, 25 de octubre de 2018

Desarrollo de paquetes en Go

Cuando desarrollamos aplicaciones, hemos de organizar bien nuestro código a base de dividir y reutilizar el código mediante funciones, pero nuestras aplicaciones pueden hacerse cada vez más y más grandes, por lo que será necesario organizar todas las funciones en paquetes.

¿Qué es un paquete

Un paquete es, básicamente, un conjunto de funciones que comparten una utilidad o una funcionalidad en común. Viene a funcionar como una librería de una temática concreta.

Go viene con una serie de librerías estándar que ofrece a los programadores un surtido rico de funciones de todo tipo: gestión de entrada y salida, matemáticas, archivos comprimidos, recursos de red, recursos del sistema operativo, gestión de imágenes, etc.

Como desarrolladores podemos crear nuestros propios paquetes y reutilizar sus funciones en nuestros programas. También podemos compartir nuestros paquetes con la comunidad para que puedan beneficiarse de su utilidad.

¿Cómo se organiza un paquete?

Para crear un paquete, es necesario crear un directorio con el nombre del paquete. Dentro de dicho directorio podemos tener tantos archivos de código .go como necesitemos, donde desarrollaremos las funciones, variables y constantes necesarias. Cada uno de estos archivos debe incluir, como primera línea, la palabra clave package, con el nombre del paquete.

Automáticamente, todos los archivos de un paquete, compartirán el código, como si de un único archivo se tratase. Esto nos permite organizar mejor nuestro código, ya que el paquete podría tener el nombre de la funcionalidad genérica, y cada archivo podría ser un nivel de afinamiento de esa funcionalidad.

Por ejemplo, podriamos definir un paquete llamado matematicas, y tener un archivo de código llamado ecuaciones.go, otro archivo llamado integrales.go, otro archivo llamado algebra.go, etc. Cada uno de estos archivos contendría un conjunto de funciones específicas.

Visibilidad en un paquete

En el capítulo "Visibilidad de datos y funciones en Go", aprendimos cuál era la visibilidad de las variables, constantes y funciones dentro de un archivo de código en Go.

La magia de los paquetes se basa en que todos los archivos del mismo paquete comparten las mismas pautas de visibilidad, como si se tratase de un único archivo. Por tanto, una función en un archivo puede invocar a otra función en otro archivo, o bien puede acceder a una variable de nivel superior de otro archivo de código, siempre y cuando dichos archivos sean del mismo paquete.

Una característica especial de los paquetes es que podemos definir variables, constantes y funciones de ámbito público, es decir, que pueden ser accedidos desde otras aplicaciones o desde otros paquetes que puedan utilizarlos. Esta característica se obtiene, simplemente, con poner la primera letra del nombre del recurso en mayúscula.

// PI es una constante publica
const PI = 3.141519

// AreaCircunferencia es una funcion publica
func AreaCircunferencia(radio float64) float64 {
   return PI * (radio * radio)
}

Importar un paquete

Para utilizar un paquete es necesario importar dicho paquete mediante la palabra clave import.

import "fmt"

En este ejemplo estamos importante el paquete estándar de Go llamado fmt, el cual nos permite utilizar funciones que controlan la entrada y salida de datos a diferentes dispositivos, como la pantalla o el disco.

Si queremos utilizar varios paquetes, podemos repetir esta línea por cada uno de los paquetes, o bien especificando la lista de paquetes dentro de unos paréntesis:

import (
   "fmt"
   "territoriogo/tutorial/11-paquetes/paquete"
)

Notas:

  • Para importar un paquete estándar de Go, simplemente hay que indicar el nombre del paquete.
  • Para una mejor organización, los paquetes se ubican en una ruta especificada por la variable de sistema $GOPATH. Para importar un paquete ubicado en esta ruta, simplemente hay que indicar el nombre del paquete
  • En este ejemplo, el paquete hay sido ubicado en un directorio más profundo en $GOPATH. Por dicho motivo, hay que especificar la ruta completa.

Uso de los recursos de un paquete

Una vez importado el paquete, podemos utilizar sus recursos (variables, constantes y funciones) especificando el nombre del paquete, seguido de un punto y del nombre del recurso.

   fmt.Println("Territorio Go")

Hay que recordar que sólo podremos usar los recursos públicos del paquete, cuyo nombre comenzará por una letra en mayúscula.

Ejemplo

Un ejemplo vale más que mil explicaciones. Para ello, crearemos un paquete llamado paquete. Dentro de este paquete crearemos dos archivos de código. Al primero lo llamaremos paquete.go, y su código será el siguiente:

package paquete

import "fmt"

// 'salario' solo se puede ver
// en el paquete 'paquete'
var salario = 12345.67

// Edad la puede ver el paquete
// y aquellos que importen el paquete
// Al poner la primera letra en
// mayusculas, se convierte en publica
var Edad = 47

// funcionPrivada solo es visible
// dentro del paquete 'paquete'
func funcionPrivada() {
   // 'esCasado' solo es visible en este metodo
   var esCasado = true

   fmt.Println("paquete > funcionPrivada() > salario: ", salario)
   fmt.Println("paquete > funcionPrivada() > Edad: ", Edad)
   fmt.Println("paquete > funcionPrivada() > esCasado: ", esCasado)
}

// FuncionPublica es visible
// dentro del paquete y donde se importe el paquete
// Al poner la primera letra en mayusculas,
// se convierte en metodo publico
func FuncionPublica() {
   // 'sabeGo' solo es visible en este metodo
   var sabeGo = true

   fmt.Println("paquete > FuncionPublica() > salario: ", salario)
   fmt.Println("paquete > FuncionPublica() > Edad: ", Edad)
   fmt.Println("paquete > FuncionPublica() > sabeGo: ", sabeGo)

   // Invoca a funcion privada en mismo archivo y paquete
   funcionPrivada()
}

// Calculo es una funcion publica
// Invoca a una funcion privada en otro archivo
// del mismo paquete, y retorna el resultado
func Calculo(a, b int) int {
   return sumatorio(a, b)
}

El segundo archivo de código se llamará paquete2.go, y tendrá el siguiente código:

package paquete

// PI es una constante publica
const PI = 3.141519

// AreaCircunferencia calcula el area de
// la circunferencia a partir de su radio
// Funcion publica
func AreaCircunferencia(radio float64) float64 {
   return PI * (radio * radio)
}

// Funcion privada. Solo es visible en el paquete
func sumatorio(a, b int) int {
   return a + b
}

Todos los recursos cuyo nombre comience con una letra en minúscula, son privados, y sólo pueden ser accedidos, de forma exclusiva, por otros recursos del mismo paquete.

Todos los recursos cuyo nombre comience con una letra en mayúscula, son publicos, y podrán ser accedidos por cualquier aplicación que utilice dicho paquete.

En el código de cualquiera de los archivos del paquete podemos usar todos los recursos (tanto públicos como privados), ubicados dentro del mismo archivo o en otro archivo del mismo paquete.

Para finalizar, crearemos un programa que utilizará el paquete, por lo que éste no debe estar dentro del directorio del paquete. Su código será el siguiente:

package main

import (
   "fmt"
   "territoriogo/tutorial/11-paquetes/paquete"
)

func main() {
   // Acceso a las variables publicas
   fmt.Println("main() > paquete.Edad: ", paquete.Edad)
   fmt.Println("main() > paquete.PI: ", paquete.PI)

   // Invocaciones de funciones publicas
   paquete.FuncionPublica()

   var resultado = paquete.AreaCircunferencia(2.15)
   fmt.Println("main() > resultado: ", resultado)

   var suma int = paquete.Calculo(12, 5)
   fmt.Println("main() > suma: ", suma)
}

El resultado será el siguiente:

$ go run paquetes.go
main() > paquete.Edad:  47
main() > paquete.PI:  3.141519
paquete > FuncionPublica() > salario:  12345.67
paquete > FuncionPublica() > Edad:  47
paquete > FuncionPublica() > sabeGo:  true
paquete > funcionPrivada() > salario:  12345.67
paquete > funcionPrivada() > Edad:  47
paquete > funcionPrivada() > esCasado:  true
main() > resultado:  14.5216715775
main() > suma:  17

Enlaces de interés

No hay comentarios:

Publicar un comentario