Introducción a Go

No soy ningún experto en Go, sólo alguien que está experimentando con este lenguaje. Aquí hay algunos ejemplos sencillos, para que quien ya haya programado en algún otro lenguaje puede comparar (si no has programado nunca, quizá todo sea demasiado poco detallado).

Después de cada ejemplo, incluiré alguna aclaración que ayude a entender las peculiaridades de ese ejemplo. En este primer acercamiento, los ejemplos serán programas simples y "no interactivos", que se puedan probar en la propia página de Go.

01.- Escribir en pantalla un texto sencillo

 
package main
 
import "fmt"
 
func main() {
    fmt.Println("Hola")
}    
 

Aclaraciones:

  • "main" es el nombre del programa (paquete, package) principal. Esa primera línea deberá existir en cualquier programa sencillo, aunque quizá no sea el único "paquete" que forme un programa más complejo
  • "fmt" es el paquete de "entrada y salida formateada", que se usará para escribir datos en pantalla o (más adelante) para leer datos desde el teclado.
  • El cuerpo del programa es la "función main".
  • Nuestro programa se limita a escribir "Hola" en la pantalla (y avanzar de línea tras escribirlo).

02.- Realizar operaciones aritméticas

 
package main
 
import "fmt"
 
func main() {
    fmt.Println("Suma: ", 2+3)
    fmt.Println("Resta: ", 3-2)
    fmt.Println("Producto: ", 2*3)
    fmt.Println("Cociente: ", 7/2)
    fmt.Println("Resto: ", 7%2)
}
 
  • Nada debería sorprender a quien ya ha programado algo: son las habituales, con la sintaxis que se usa en los lenguajes que derivan de C.
  • La única peculiaridad es que no se usa punto y coma al final de cada línea.

03.- Comparaciones simples

 
package main
 
import "fmt"
 
func main() {
    if 2 > 1 {
        fmt.Println("2 es mayor que 1")
    } else if 1 > 2 {
        fmt.Println("1 es mayor que 2")
    } else {
        fmt.Println("2 es igual que 1")
    }
}
 
  • La primera diferencia con los lenguajes "tipo C" es que la condición se indica sin paréntesis.
  • Una segunda diferencia es que los pasos que hay que dar se indican obligatoriamente entre llaves.
  • En caso de que haya que indicar qué hacer si no se cumple la condición, los "else" deben aparecer en la misma línea que la llave de cierre (es una consecuencia de no usar puntos y coma para indicar el final de una orden).
  • Los operadores de comparación son los habituales en los lenguajes que derivan de C: igual que (==), mayor que (>), mayor o igual que (>=), menor que (<), menor o igual que (<=), distinto de (!=). Se pueden enlazar varias condiciones con && (y), || (o), | (no).

04.- Estructuras repetitivas simples

 
package main
 
import "fmt"
 
func main() {
    for i:=1; i<=10; i++ {
        fmt.Println(i)
    }
}
 
  • Al igual que pasaba con "if", no se utilizan paréntesis.
  • Además, el valor inicial se indica con ":=".
  • Y no es necesario (en este caso) declarar la variable.

Se puede usar "i=1" para dar el valor inicial, con una sintaxis que recuerda más a la de C, pero en ese caso sí es necesario declarar la variable:

 
import "fmt"
 
func main() {
    var i int
    for i=1; i<=10; i++ {
        fmt.Println(i)
    }
}
 

Para declarar una variable, se usa la palabra "var", seguida del nombre de la variable y de su tipo ("int", en este caso, para indicar que es un número entero).


05.- Funciones

 
package main
 
import "fmt"
 
func suma(x, y int) int {
    return x + y
}
 
func main() {
    fmt.Println(suma(2, 3))
}
 
  • Las funciones, como ya habíamos visto con "main", se declaran con la palabra "func".
  • Los parámetros se indican con su nombre y (a continuación, igual que pasaba con la declaración de variables) el tipo de datos correspondiente.
  • Si la función debe devolver un valor, se indica con la palabra "return".
  • El tipo de ese valor devuelto se indica al final de la cabecera de la función.

06.- Comparaciones múltipes

package main
 
import "fmt"
 
func main() {
	letra := 'a'
	switch letra {
		case 'a','e','i','o','u':
			fmt.Println("Es una vocal")
		case '0','1','2','3','4','5','6','7','8','9':
			fmt.Println("Es una cifra")
		default:
			fmt.Println("Es otro símbolo")
	}
}
 

  • Los casos de la orden "switch" no necesitan "break": terminan con su última orden, y no se pasa automáticamente de un caso al siguiente.
  • Se pueden indicar varios valores posibles en un mismo caso, separándolos entre comas.
  • El análisis se interrumple en cuanto se cumple un caso, y dejan de analizarse los demás.

package main
 
import "fmt"
 
func main() {
	var letra byte
	letra = 'c'
	switch {
		case letra=='a' ||  letra=='e' ||  letra=='i' ||  letra=='o' ||  letra=='u':
			fmt.Println("Es una vocal")
				case letra >='b' && letra <= 'z':
			fmt.Println("Es una consonante")
		case letra >='0' && letra <= '9':
			fmt.Println("Es una cifra")
		default:
			fmt.Println("Es otro símbolo")
	}
}
 

  • Existe una sintaxis alternativa, que recuerda mucho a varios "if" consecutivos.
  • En este caso, no se indica variable en "switch" y las condiciones pueden ser más complejas, con sintaxis como la de "if".

07.- Importar varias "bibliotecas"

package main
 
import (
	"fmt"
	"math"
)
 
func main() {
	radio := 3.5;
	circunferencia := 2 * math.Pi * radio;
	fmt.Println("Circunferencia = ", circunferencia)
	circulo := math.Pi * radio * radio;
	fmt.Println("Circulo = ", circulo)
}
 

  • Si tenemos que incluir varias "bibliotecas", podemos usar varias órdenes "import", o bien, indidcar todas ellas entre paréntesis.
  • Por ejemplo, "math" contiene funciones matemáticas, junto con algunas constantes como el número "Pi".

08.- Dar varios valores a la vez

package main
 
import "fmt"
 
func intercambiar(x, y int) (int, int) {
	return y, x
}
 
func main() {
	var a, b int = 4, 6
	c, d := intercambiar(a, b)
	fmt.Println(c, d)
}

  • Se puede dar valor a varias variables a la vez, en el mismo momento de declararlas, pero todos los valores se indican al final de la línea, después del tipo de datos.
  • Es más, una función puede devolver varios valores.

09.- Structs

package main
 
import "fmt"
 
type Punto struct {
	X int
	Y int
	Z int
}
 
func main() {
	v := Punto{1, 2, -4}
	v.Y = 3
	fmt.Println("X vale ", v.X)
	fmt.Println("Y todo el punto es ",v)
 
}
 

  • Al definir el struct, para cada campo se indicará primero el nombre y luego el tipo de datos.
  • Se puede dar valor inicial a todos los campos, detallándolos entre llaves, o bien acceder uno por uno, separando el nombre de la variable y el nombre del campo por un punto.
  • Se puede mostrar el valor de todo un struct (los valores aparecerán entre llaves, separados por espacios).

El resultado sería

X vale  1
Y todo el punto es  {1 3 -4}

10.- Arrays

package main
 
import "fmt"
 
func main() {
    pares := []int {2, 4, 6, 8, 10}
 
    // Mostramos los datos uno por uno
    for i := 0; i < len(pares); i++ {
        fmt.Printf("posicion %d, valor %d\n",
            i, pares[i])
    }
 
    // Mostramos todo el array
    fmt.Println("Pares:", pares)
 
    // De la posicion 1 a la 3
    fmt.Println("pares[1:4] ==", pares[1:4])
 
    // Desde el principio a la 3
    fmt.Println("pares[:3] ==", pares[:3])
 
    // Desde la 2 hasta el final
    fmt.Println("pares[2:] ==", pares[2:])
}
 

  • Si se saben los valores iniciales del array, se pueden indicar entre llaves.
  • Se accede a cada elemento con corchetes. El tamaño se puede saber con "len".
  • Se puede obtener un fragmento del array ("slice") usando el formato "pares[desde:hasta]" ("hasta" no se incluye en el resultado, sino "hasta-1". Si se omite el primero de los extremos, el fragmento comenzará en el primer dato; si se omite el dato final, se extraerá hasta el último dato del array.

Su resultado sería

posicion 0, valor 2
posicion 1, valor 4
posicion 2, valor 6
posicion 3, valor 8
posicion 4, valor 10
Pares: [2 4 6 8 10]
pares[1:4] == [4 6 8]
pares[:3] == [2 4 6]
pares[2:] == [6 8 10]

Seguirá...

¿Hay más? Claro. Por ejemplo: "mapas", ficheros, interacción con el usuario, servicios de red... ¿Cuando? Pronto... si veo que hay gente interesada...