Cómo escribir código Go

Introducción

Este documento muestra el desarrollo de un sencillo paquete Go e introduce la herramienta go, la manera estándar para descargar, construir e instalar paquetes y órdenes Go.

La herramienta go requiere que organices tu código en una manera específica. Por favor lee cuidadosamente este documento. Este explica la manera más sencilla de configurar y ejecutar tu instalación de Go.

Disponemos de una explicación similar en video (en inglés).

Organizando el código

Ambiente de trabajo

La herramienta go está diseñada para trabajar con código de fuente abierta mantenido en repositorios públicos. Aunque no es necesario publicar tu código, el modelo para configurar el ambiente de trabajo es igual si lo haces o no.

El código Go se debe mantener dentro de un ambiente de trabajo. Un ambiente de trabajo es una jerarquía de directorios con tres ramas en su raíz:

  • src contiene los archivos de código fuente Go organizados en paquetes (un paquete por directorio),
  • pkg contiene objetos paquete, y
  • bin contiene las órdenes ejecutables.

La herramienta go construye paquetes fuente e instala los binarios resultantes a los directorios pkg y bin.

El subdirectorio src típicamente contiene múltiples repositorios de control de versiones (tal como Git o Mercurial) que siguen la pista al código fuente del desarrollo de uno o más paquetes.

Para darte una idea de cómo se ve un ambiente de trabajo en la práctica, aquí tienes un ejemplo:

bin
    hola                        # orden ejecutable
    yasalio                     # orden ejecutable
pkg
    linux_amd64
        github.com/gitnacho/ejemplo
            utilcadenas.a       # objecto paquete
src
    github.com/gitnacho/ejemplo
        .git/                   # metadatos del repositorio git
        hola
            hola.go             # fuente de la orden
        yasalio
            main.go             # fuente de la orden
            main_test.go        # fuente de la prueba
        utilcadenas
            reverso.go          # fuente del paquete
            reverso_test.go     # fuente de la prueba

Este ambiente de trabajo contiene un repositorio (ejemplo) que comprende dos órdenes (hola y yasalio) y una biblioteca (utilcadenas).

Un ambiente de trabajo típico debería tener varios repositorios fuente conteniendo muchos paquetes y órdenes. La mayoría de los programadores Go mantienen todo su código fuente y dependencias de Go en un único ambiente de trabajo.

Las órdenes y bibliotecas se construyen de diferentes clases de paquetes fuente. Hablaremos sobre esta distinción más adelante.

La variable de entorno GOPATH

La variable de entorno GOPATH especifica la ubicación de tu ambiente de trabajo. Probablemente esta puede ser la única variable de entorno que necesitarás configurar cuando desarrollas código Go.

Para empezar, crea un directorio para tu ambiente de trabajo y configura GOPATH consecuentemente. Tu ambiente de trabajo se puede localizar en dónde quieras, no obstante, en este documento utilizaremos $HOME/go. Ten en cuenta que esta no debe ser la misma ruta que tu instalación de Go.

$ mkdir $HOME/go
$ export GOPATH=$HOME/go

Por comodidad, añade el subdirectorio bin del ambiente de trabajo a tu PATH:

$ export PATH=$PATH:$GOPATH/bin

Rutas de paquetes

A los paquetes de la biblioteca estándar se les asignan rutas cortas tal como "fmt" y "http/net". Para tus propios paquetes, debes escoger una ruta base que sea poco probable pueda colisionar con futuras adiciones a la biblioteca estándar u otras bibliotecas externas.

Si mantienes tu código en algún repositorio fuente, entonces deberías utilizar la raíz de ese repositorio fuente como tu ruta base. Por ejemplo, si tu cuenta GitHub está en github.com/usuario, esa debería ser tu ruta base.

Ten en cuenta que no necesitas publicar tu código a un repositorio remoto antes de que lo puedas construir. solo es un buen hábito para organizar tu código como si algún día lo fueras a publicar. En la práctica puedes escoger cualquier nombre de ruta arbitrario, siempre y cuando sea único en la biblioteca estándar y en el ecosistema Go.

Utilizaremos github.com/usuario como nuestra ruta base. Crea un directorio dentro de tu ambiente de trabajo en el cual mantendrás el código fuente:

$ mkdir -p $GOPATH/src/github.com/usuario

Tu primer programa

Para compilar y correr un sencillo programa, primero escoge una ruta para el paquete (utilizaremos github.com/usuario/hola) y crea un directorio para el paquete correspondiente dentro de tu ambiente de trabajo:

$ mkdir $GOPATH/src/github.com/usuario/hola

Luego, crea un archivo llamado hola.go dentro de ese directorio, conteniendo el siguiente código Go.

package main

import "fmt"

func main() {
    fmt.Printf("Hola, mundo.\n")
}

Ahora puedes construir e instalar el programa con la herramienta go:

$ go install github.com/usuario/hola

Ten en cuenta que puedes ejecutar esta orden desde cualquier lugar en tu sistema. La herramienta go encuentra el código fuente buscando el paquete github.com/usuario/hola dentro del ambiente de trabajo especificado por GOPATH.

También puedes omitir la ruta del paquete si ejecutas go install desde el directorio del paquete:

$ cd $GOPATH/src/github.com/usuario/hola
$ go install

Estas instrucciones construyen la orden hola, produciendo un ejecutable binario. Esto instala el binario en el directorio bin del ambiente de trabajo como hola (o, bajo Windows, hola.exe). En nuestro ejemplo, este será $GOPATH/bin/hola, el cual está en $HOME/go/bin/hola.

La herramienta go solo producirá salida cuando ocurra un error, así que si estas órdenes no producen ninguna salida es porque se han ejecutado satisfactoriamente.

Ahora puedes ejecutar el programa escribiendo la ruta completa en la línea de órdenes:

$ $GOPATH/bin/hola
Hola, mundo.

O, suponiendo que añadíste $GOPATH/bin a tu PATH, solo escribe el nombre del binario:

$ hola
Hola, mundo.

Si estás utilizando un sistema de control de versiones, ahora sería un buen momento para iniciar un repositorio, añadir los archivos y enviar tu primer entrega. Una vez más, este paso es opcional: no es necesario utilizar el control de versiones para escribir código Go.

$ cd $GOPATH/src/github.com/usuario/hola
$ git init
Inicia repositorio Git vacío en /home/user/go/src/github.com/usuario/hola/.git

$ git add hola.go
$ git commit -m "entrega inicial"
[master (root-commit) 0b4507d] entrega inicial
 1 archivo cambió, 1 insercion(+)
  crea modo 100644 hola.go

Dejamos el envío del código a un repositorio remoto como ejercicio para el lector.

Tu primer biblioteca

Vamos a escribir una biblioteca y a usarla desde el programa hola.

De nuevo, el primer paso es escoger una ruta para el paquete (utilizaremos github.com/usuario/utilcadenas) y creamos el directorio del paquete:

$ mkdir $GOPATH/src/github.com/usuario/utilcadenas

A continuación, crea un archivo llamado reverso.go en ese directorio con el siguiente contenido.

// utilcadenas este paquete contiene útiles funciones para trabajar
// con cadenas de caracteres.
package utilcadenas

// Reverso invierte su argumento s dejándolo legible de izquierda
// a derecha.
func Reverso(s string) string {
    r := []rune(s)
    for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
        r[i], r[j] = r[j], r[i]
    }
    return string(r)
}

Ahora, comprueba que el paquete compila con go build:

$ go build github.com/usuario/utilcadenas

O, si estás trabajando en el directorio fuente del paquete, justo:

$ go build

Esto no producirá un archivo. Para ello, tienes que utilizar go install, que coloca el objeto paquete dentro del directorio pkg del ambiente de trabajo.

Después de confirmar la construcción del paquete utilcadenas, modifica tu hola.go original (que está en $GOPATH/src/github.com/usuario/hola) para utilizarlo:

package main

import (
    "fmt"
    "github.com/usuario/utilcadenas"
)

func main() {
    fmt.Printf(utilcadenas.Reverso("!oG ,aloH¡"))
}

Siempre que la herramienta go instala un paquete o binario, también instala todas las dependencias que tenga. Por lo tanto cuando instalas el programa hola

$ go install github.com/usuario/hola

Automáticamente también instalará el paquete utilcadenas.

Al ejecutar la nueva versión del programa, deberías ver un nuevo mensaje, invertido:

$ hola
¡Hola, Go!

Después de los pasos anteriores, tu ambiente de trabajo se parecerá a este:

bin
        hola                    # orden ejecutable
pkg
        linux_amd64/            # esto reflejará tu SO y arquitectura
        github.com/usuario
                utilcadenas.a   # objecto paquete
src
        github.com/usuario
            hola
                hola.go         # fuente de la orden
        utilcadenas
                reverso.go      # fuente del paquete

Ten en cuenta que go install colocó el objeto utilcadenas.a en un directorio dentro de pkg/linux_amd64 que refleja tu directorio fuente. Esto es a modo de que futuras invocaciones a la herramienta go puedan encontrar el objeto paquete y evitar recompilar innecesariamente el paquete. La parte linux_amd64 está allí para ayudar en recompilaciones cruzadas, y refleja el sistema operativo y arquitectura de tu sistema.

Las órdenes ejecutables se enlazan estáticamente; los objetos paquete no es necesario que estén presentes para ejecutar los programas Go.

Nombre de paquetes

La primer declaración en un archivo fuente de Go tiene que ser:

package nombre

Dónde nombre es el nombre predeterminado del paquete para importaciones. (Todos los archivos en un paquete tienen que utilizar el mismo nombre).

Una convención en Go es que el nombre del paquete es el último elemento de la ruta de importación: el paquete importado como "crypto/rot13" se debería llamar rot13.

Las órdenes ejecutables siempre tienen que usar package main.

No hay ningún requisito para que los nombres de paquete sean únicos entre todos los paquetes enlazados a un solo binario, solo que las rutas de importación (sus nombres de archivo completos) sean únicos.

Ve Go eficiente para aprender más sobre las convenciones de nomenclatura en Go.

Probando

Go tiene una ligera plataforma de pruebas compuesta de la orden go test y el paquete testing.

Escribes una prueba creando un archivo con un nombre que termine en _test.go el cual contiene las funciones llamadas TestXXX con la firma func (t *testing.T). La plataforma de pruebas corre cada una de esas funciones; si la función invoca a una función de fallo tal como t.Error o t.Fail, se considerada que la prueba falló.

Añade una prueba al paquete utilcadenas creando el archivo $GOPATH/src/github.com/usuario/utilcadenas/reverso_test.go conteniendo el siguiente código Go.

package utilcadenas

import "testing"

func TestReverso(t *testing.T) {
    casos := []struct {
        ingresada, deseada string
    }{
        {"Hola, mundo", "odnum ,aloH"},
        {"Hola, 世界", "界世 ,aloH"},
        {"", ""},
    }
    for _, c := range casos {
        obtuve := Reverso(c.ingresada)
        if obtuve != c.deseada {
            t.Errorf("Reverso(%q) == %q, deseada %q", c.ingresada, obtuve, c.deseada)
        }
    }
}

Entonces corre la prueba con go test:

$ go test github.com/usuario/utilcadenas
ok      github.com/usuario/utilcadenas 0.165s

Como siempre, si estás corriendo la herramienta go desde el directorio del paquete, puedes omitir la ruta del paquete:

$ go test
ok      github.com/usuario/utilcadenas 0.165s

Corre go help test y ve la documentación del paquete testing para más detalles.

Paquetes remotos

Una ruta de importación puede describir cómo obtener el código fuente del paquete utilizando un sistema de control de versiones tal como Git o Mercurial. La herramienta go utiliza esta propiedad para automáticamente descargar paquetes desde repositorios remotos. Por ejemplo, los fragmentos de código descritos en este documento también están mantenidos en un repositorio Git hospedado en Github, github.com/gitnacho/ejemplo. Si incluyes el URL del repositorio en la ruta de importación del paquete, go get lo descargará, construirá e instalará automáticamente:

$ go get github.com/gitnacho/ejemplo/hola
$ $GOPATH/bin/hola
¡Hola, ejemplos Go!

Si el paquete especificado no está presente en un ambiente de trabajo, go get lo colocará dentro del primer ambiente de trabajo especificado por GOPATH. (Si el paquete ya existe, go get omitirá la descarga remota y se comportará igual que go install).

Después de emitir la orden go get anterior, ahora el árbol de directorios del ambiente de trabajo se debería parecer a este:

bin
    hello                       # orden ejecutable
pkg
    linux_amd64
        github.com/gitnacho/ejemplo
            utilcadenas.a       # objeto paquete
        github.com/usuario
            utilcadenas.a       # objecto paquete
src
    github.com/gitnacho/ejemplo
        .git/                   # metadatos del repositorio Git
        hola
            hola.go             # fuente de la orden
        utilcadenas
            reverso.go          # fuente del paquete
            reverso_test.go     # fuente de pruebas
    github.com/usuario
        hola
            hola.go             # fuente de la orden
        utilcadenas
            reverso.go          # fuente del paquete
            reverso_test.go     # fuente de pruebas

La orden hola hospedada en Github depende del paquete utilcadenas dentro del mismo repositorio. Las importaciones en el archivo hola.go utilizan la misma convención de las rutas de importación, por lo tanto la orden go get también es capaz de localizar e instalar el paquete dependiente.

import "github.com/gitnacho/ejemplo/utilcadenas"

Esta convención es la manera más fácil de permitir que tus paquetes Go estén disponibles para que otros los utilicen. El Wiki de Go y godoc.org proporcionan listas de proyectos Go externos.

Para más información sobre el uso de repositorios remotos con la herramienta go, ve go help importpath.

Algo más

Suscríbete a la lista de correo golang-announce para recibir notificaciones de cuándo se liberará una nueva versión estable de Go.

Ve Go eficiente para ver algunos consejos sobre cómo escribir claro e idiomático código Go.

Toma Un paseo por Go para aprender adecuadamente el lenguaje.

Visita la página de documentación para un conjunto de artículos que profundizan en el lenguaje Go, sus bibliotecas y herramientas.

Consiguiendo ayuda

Para ayuda en tiempo real, pregunta a los serviciales gophers en el canal #go-nuts del servidor IRC Freenode.

La lista de correo oficial para discusión del lenguaje Go es Go Nuts.

Reporta fallos utilizando el Gestor de incidencias Go.

En su mayor parte este libro se reproduce a partir del trabajo creado y compartido por Google traducido al Español y se usa de acuerdo a los términos descritos en la Licencia Creative Commons 3.0 Attribution.