En este tutorial hablaremos del lenguaje Golang de Google. O también llamado Go. Vamos a ver las características principales y luego haremos un pequeño programa de prueba para ilustrar como funciona.

El lenguaje Go o también llamado Golang fue creado por Google a mediados del año 2009, y hasta entonces no ha parado de incrementar su popularidad, hasta situarse en el Top 10 de los lenguajes de programación más utilizados hoy en día.

Principalmente se creó para la parte del backend, donde era el reino de Java y PHP, y Ruby en menor medida. También lo han vendido como el lenguaje C del siglo XXI.

 

Características

Es un lenguaje de programación estructurado y compilado. Está disponible para Windows, Mac OS y Linux.

Dispone de un recolector de basura del mismo modo que Java, con lo que no hay que llevar una contabilidad de punteros en memoria.

La sintaxis es parecida a C y contiene algunos parecidos con Python. Aunque la manera de definir el tipo de las variables es precisamente poniendo su tipo al final de la variable. Además permite definir el tipo de varias variables al mismo tiempo. 

Algo interesante es que se pueden devolver más de una variable de retorno de una función.

Esto es sin duda una de las marcas de la casa, la sencillez y facilidad a la hora de programar, facilitando la vida al programador.

En principio tiene la posibilidad de programación orientada a objetos aunque para los que conocen Java, su interpretación es algo especial. De hecho no permite la herencia.

Es un lenguaje de programación compilado. Se genera código nativo para cada plataforma.

A nivel de concurrencia lo borda gracias a las gorutines, haciendo que la programación concurrente sea todo un placer.

Se estructura en paquetes (algo similar a Java), y existe un paquete especial llamado "main" que contiene una función llamada main(), que es el punto de entrada de un programa. Algo parecido al main de Java y C.

Como siempre, es mejor aprender practicando, así que vamos a instalar primero el Golang y vamos a realizar un programa de ejemplo.

 

Instalar Go

Para Windows prodemos descargar el programa de https://golang.org/doc/install?download=go1.8.3.windows-amd64.msi

y para Linux podemos hacer un apt-get install golang.

Como editor de código vamos a usar el Microsoft Visual Code, que tiene un plugin muy bueno para Go.

 

Crear el programa

Para empezar creamos una carpeta llamada spider y creamos un fichero main.go dentro de ella.

La estructura inicial del programa será: 

package main

import "fmt"

func main(){
   fmt.Println("Run")
}

Este es el esqueleto básico.  Vemos el uso del paquete por defecto, la importación de fmt, que sirve para leer y escribir por terminal y el uso de la función main.

 Todos los programas go, tienen que tener un punto de entrada y ese es precisamente el método main del package main.

Por cierto, el punto y coma no es necesario en go.

Para compilar el programa hay que escribir go build main.go y nos generará un fichero ejecutable.

Otro comando interesante es gofmt -w main.go, que se encarga de formatear el código y sobreescribirlo (por eso el flag -w).

Y otro más es goimports -w main.go, que se encarga de importar y corregir los paquetes que nos hayamos olvidado.

 

Ejecutar el programa

Para ejecutarlo en el terminal también se puede escribir go run main.go y nos sacará por pantalla Run. Así de simple. Es un modo fácil de testear los programas sin tener que compilarlos.

Vamos a crear un programa para que se descargue una página de internet.

Para ello el programa tendrá que pedir por la consola la dirección (url) y luego accederá e imprimirá el contenido.

Para la entrada de parámetros usaremos el paquete "flag" .

 

func main(){

	weburl:=flag.String("url","google.com","La URL a buscar")
	flag.Parse()
	
	fmt.Println("Run:")
	fmt.Println(*weburl)
}

 A continuación con la ayuda del paquete net invocaremos a la url y con el paquete ioutils dispondremos de métodos para lectura y escritura.

También podemos usar el paquete os para salir del programa en caso de error.

Así pues el ejemplo quedaría de la siguiente manera: 

 

package main

import ("fmt"
 "flag"
 "net/http"
 "io/ioutil"
 "os")

func main(){

	weburl:=flag.String("url","http://google.com","La URL a buscar")
	flag.Parse()
	
	fmt.Println("Run:")
	fmt.Println(*weburl)
	resp, err := http.Get(*weburl)  
        if err != nil {
   		fmt.Println("Error http:", err)
		os.Exit(1)
	}

  	body, err := ioutil.ReadAll(resp.Body)  
        if err != nil {                                      
  		fmt.Println("Error lectura:", err)
		os.Exit(1)
	} 

  	fmt.Println(string(body))   
}

 Como se puede ver, las sentencias if-else no requieren paréntesis, pero sí las llaves de apertura y cierre.

También se puede ver que para asignar una variable, se puede usar el ":=". Este es un modo fácil de asignar el valor y el tipo a la variable. 

En Go existen los tipos habituales: int, bool, string, []int, etc. Si no asignamos un valor a la variable, Go lo pondrá a 0,  "",  0.0, false, nil.

Por otro lado, se puede asignar una variable del modo más habitual, definiendo su tipo, con la sentencia var. Así var cadena string = "cadena"

Los arrays se definen como var lista [10]string y se pueden informar los valores como es habitual: lista[0] = "Hola"

Podemos definir lo que llaman slices, que son arrays sin un tamaño fijado, que pueden crecer dinámicamente: var lonchas []string

Para ello se utiliza la sentencia append(lonchas, "cadena"), que añade elementos al array. O de un modo más compacto: lonchas []string{"uno","dos"}

Luego para recorrer los elementos de un slice se puede hacer con un bucle:

for i,elem := range lonchas { ... }

Consejo: Mira la documentación oficial para conocer más sobre range y la variable no usada "_".

 

Otro modo de leer los parámetros de entrada es con os.Args. Esto es un array de elementos, donde el [0] es el nombre del ejecutable, el [1] el primer parámetro, y así sucesivamente. Para leer la longitud de un array se puede usar la función len(variable).

 Si queremos compilar el programa escribiremos go build spider.go y se generará un ejecutable.

 

 Definir estructuras

Un modo de enriquecer los tipos de datos es con el uso de estructuras.

Se definen fuera de la función main, y se inicializan dentro de la función main, del estilo:

type coche struct {
   marca string
 modelo string
puertas int
}

Luego se inicilizaría tal como micoche := coche{marca: "seat", modelo: "ibiza", puertas: 3}

Estas estructuras también pueden tener métodos, por ejemplo el color del coche y se definen con la sentencia:

func (c coche) color() string { ... }

Dentro del método se podría acceder a las propiedades de la estructura con el punto como c.marca o c.modelo.

Esto sería lo más parecido a orientación a objetos que Go puede tener. Exsite además la sentencia interface que permite definir métodos comunes que deben implementar las diferentes estructuras.

 Nota: Para que una función se pueda usar fuera de su paquete hay que adoptar una convención de poner la primera letra en mayúsculas.

 

El puntero contrataca

Sí, de nuevo volvemos a tener punteros en Go. Es decir.

Si se define una variable cadena := "hola" y otra cadena2 := cadena. La segunda obtiene una copia del valor de la primera.

Si definimos cadena2 := &cadena   entonces la segunda obtiene una referencia al valor de la primera.

 Los métodos pueden tener punteros como parámetros, para definirlo así se usa el * antes del tipo de estructura.

 

Definir funciones

Para definir funciones, se utiliza la sintaxis:

func nombre (variable tipo) tiporetorno { ... }

Un modo curioso de implementar que una función puede devolver un error, es retornando dos variables, sí eso mismo, dos variables al mismo tiempo.

func nombre (variable tipo) (tiporetorno, error) { ... }

Para ello hay que importar el paquete errors y asignar un error tal como: 

err := errors.New("Error a")

Si queremos devolver el resultado de una función sin error, lo podemos poner a nil. De ese modo

return variableretorno, nil

Por el contrario si encontramos un error, es algo común comprobarlo, entonces logamos el mensaje y salimos del programa:

if err != nil {
   fmt.Println(err)
   os.Exit(1)
}

Un tipo especial de funciones son las gorutines, que son funciones que se ejecutan concurrentemente con el resto. Y para ello se definen con la sentencia go delante de la función.

 

Bucles

Realmente sólo vamos a usar la sentencia for, ya que no dispone de ninguna otra. Pero vamos a ver que realmente es como una navaja suiza. Nos va a permitir realizar todo tipo de bucles. Como cabía esperar, no utiliza los paréntesis, pero las llaves son obligatorias.

for expr antes 1a iterac ; condicion antes cada interac ; expr después de iterac { ... }

Por ejemplo para iterar de 0 a 9: 

for i := 0 ; i<10 ; i++ { ... }

Otro uso en la forma:

for condicion  { ... } 

sin especificar dentro del for la variable antes de la 1a iterac.

Para salir del bucle, se usa la sentencia break, como en muchos otros lenguajes de programación.

La sentencia

for { .. }

haría un bucle infinito, que se ejecutaría hasta que el programa se abortara.

 

Los tipos de datos primitivos son bool (true/false), que indica verdadero o falso; char que indica un carácter unicode de 16bit; byte (8bit), short (16bit), int (32bit) y long (64bit) que indican un número entero con signo; double y float que indica un número con coma flotante; y complex para números complejos. Las constantes se definen con const. Incluso tiene punteros. Y tipos de datos compuestos (struct).

Existe además arrays que define un array de 3 enteros, y cadenas de texto: var str string ="Hola" . Existe una palabra para designar una referencia nula de un puntero, mapa, slice (nil).

Existen varios operadores: para asignar un valor (x=3), para operar con números (+,-,*,/,%), para comparar (==, !=, <, >, <=, >=), para lógica (&&, ||, !), y para operaciones de bit (&,|,^,<<, >>).

Para escribir comentarios se pueden poner en una sola linea //comentario. Y para generar documentación de la API (gdoc) se usa // justo encima de la palabra package

Una clase abstract es una clase que no contiene implementación sólo definiciones de métodos, son clases para que las clases que la extiendan implementen su propio programa.

Por definición para ejecutar una clase tiene que implementar el método func main(), ya que es el punto de entrada para ejecutar un programa.

Las clases se organizan en paquetes que se definen al principio del código fuente package .Para utilizar estos paquetes desde otras clases se usa import "paquete/sub" o import paquete para importar todas las clases.

Cada Clase puede tener un tipo de visibilidad: private, donde variables y métodos no se pueden acceder desde fuera de la clase. Y public donde se puede acceder desde cualquier clase. Para ello si la primera letra del tipo de variable es mayúscula es visible.

Utiliza clases que derivan de error. Nosotros podemos definir nuestros propios errores para controlar el flujo del programa con struct que contenga un tipo error.

Para tratar errores no se utilizan try catch o finally como otros lenguajes. Se devuelven structs de tipo error en las funciones.

 ◂ 
 ▸