Lección 2 de 8. Las piezas básicas: cómo se declara una variable, qué vale antes de que le des nada y por qué en Go una función puede devolver dos cosas a la vez. Esto último no es un capricho de sintaxis: es la base de cómo se manejan los errores, que veremos en la lección 5.
Tres formas de declarar
var nombre string = "Ana" // tipo y valor, explícitos var edad = 34 // el tipo se deduce del valor ciudad := "Lima" // lo mismo, más corto
salidaAna 34 Lima
Las tres declaran lo mismo. En la práctica vas a usar := casi siempre, y var cuando necesites fijar el tipo a mano o declarar algo fuera de una función.
Porque esa es la limitación del atajo: := solo funciona dentro de una función.
package main x := 10 // fuera de cualquier función
no compila./main.go:3:1: syntax error: non-declaration statement outside function body
:= declara, así que exige que al menos una de las variables de la izquierda sea nueva. Repetirlo sobre la misma variable no funciona: no new variables on left side of :=. Para reasignar se usa el = de toda la vida.El valor cero: nunca hay basura
En Go una variable declarada siempre tiene un valor definido, aunque no le hayas dado ninguno. No existe el «dato sin inicializar» de C ni hace falta un null por defecto. A ese valor se le llama el valor cero del tipo.
var s string
var n int
var f float64
var b bool
var p *int
fmt.Printf("cadena=%q entero=%d decimal=%v booleano=%v puntero=%v\n", s, n, f, b, p)
salidacadena="" entero=0 decimal=0 booleano=false puntero=<nil>
| Tipo | Valor cero |
|---|---|
Números: int, float64… |
0 |
string |
La cadena vacía, "" |
bool |
false |
| Punteros, slices, maps, interfaces, funciones | nil |
struct |
Cada campo con su propio valor cero |
Esto tiene una consecuencia práctica que se agradece: un contador recién declarado ya vale cero y un booleano ya vale false, así que no hay que inicializarlos a mano.
Los tipos no se mezclan solos
Go no convierte números por su cuenta, ni siquiera entre un entero y un decimal. Esto no compila:
var entero int = 7 var decimal float64 = entero / 2
no compila./main.go:7:24: cannot use entero / 2 (value of type int) as float64 value in variable declaration
Hay que pedir la conversión:
var decimal float64 = float64(entero) / 2 fmt.Println(decimal)
salida3.5
Fíjate en dónde va la conversión. Si escribieras float64(entero / 2), la división se haría primero entre enteros y daría 3, y convertir después no recupera el medio perdido. Es el error de cálculo más común en Go y en casi cualquier lenguaje con tipos estrictos.
Funciones, y el retorno doble
Una función declara los tipos de sus parámetros y de lo que devuelve. Si varios parámetros comparten tipo, basta ponerlo una vez:
func dividir(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("no se puede dividir %v entre cero", a)
}
return a / b, nil
}
Eso de devolver dos valores es lo más característico de Go. No hay excepciones: una función que puede fallar devuelve el resultado y, al lado, un error. Cuando todo va bien, el error vale nil.
r, err := dividir(10, 4) fmt.Println(r, err) r, err = dividir(10, 0) fmt.Println(r, err)
salida2.5 <nil> 0 no se puede dividir 10 entre cero
Lo que harías de verdad no es imprimir el error sino comprobarlo, y eso tiene una forma fija que verás en todo el código de Go. La dejamos planteada aquí y la desarrollamos en la lección 5:
r, err := dividir(10, 0)
if err != nil {
// algo ha ido mal: decide qué hacer y sal
return
}
// a partir de aquí r es de fiar
Resultados con nombre
Los valores de retorno pueden llevar nombre, y entonces ya están declarados dentro de la función:
func minMax(nums []int) (menor, mayor int) {
menor, mayor = nums[0], nums[0]
for _, n := range nums {
if n < menor {
menor = n
}
if n > mayor {
mayor = n
}
}
return // devuelve menor y mayor, sin repetirlos
}
salidamenor: 2 mayor: 9
Ese return a secas se llama naked return. Es cómodo en funciones cortas como esta y se desaconseja en las largas, porque obliga a buscar arriba qué se está devolviendo. El valor real de ponerles nombre es otro: documentan la firma. (menor, mayor int) dice mucho más que (int, int).
_: _, err := dividir(10, 2) descarta el resultado y se queda solo con el error. Lo verás por todas partes.Lo que hay que llevarse
:= dentro de funciones y var fuera. Toda variable nace con un valor cero conocido. Las conversiones entre tipos numéricos son siempre explícitas. Y lo que de verdad hay que interiorizar: en Go las funciones devuelven el resultado y el error juntos, y esa pareja va a aparecer en cada línea que escribas a partir de ahora.
Todo el código de esta lección se compiló y ejecutó con Go 1.25 antes de publicarla. Los tres errores están provocados a propósito y los mensajes son los que devuelve el compilador, copiados literalmente.