El bucle for en Go es la única estructura repetitiva del lenguaje. Con ella hacemos bucles clásicos, bucles tipo while y recorridos sobre colecciones.
Si vienes de C, Java o JavaScript, estarás acostumbrado a tener un arsenal de bucles: for, while, do-while, foreach… A veces usas uno, a veces otro, y a veces discutes con tu equipo sobre cuál es más eficiente.
En Go, los diseñadores cortaron por lo sano. Solo existe el bucle for.
No hace falta nada más. El bucle for puede comportarse como los bucles tradicionales simplemente omitiendo partes de su sintaxis.
Equivalencias con otros bucles
Todas las formas habituales se expresan con for:
| Tipo de bucle tradicional | En Go se escribe… | Sintaxis |
|---|---|---|
for (i=0; i<10; i++) | for clásico | for i:=0; i<10; i++ |
while (condicion) | for condicional | for condicion |
while (true) | for infinito | for |
do-while | No existe | Se simula con un for infinito + if break al final |
El bucle for clásico
Esta es la forma que todos conocemos, idéntica a C o Java, pero sin paréntesis (igual que el if).
Sintaxis: for inicialización; condición; post { ... }
package main
import "fmt"
func main() {
// Imprimir del 0 al 4
for i := 0; i < 5; i++ {
fmt.Println("Contador:", i)
}
}Fíjate que la variable i se declara con := dentro del propio bucle. Esto significa que i solo existe dentro del bucle. Si intentas acceder a ella fuera, tendrás un error.
El for como while
En otros lenguajes usamos while cuando no sabemos cuántas iteraciones vamos a hacer, sino que dependemos de una condición booleana.
En Go, para conseguir esto, simplemente eliminamos la parte de inicialización y la de post. Dejamos solo la condición.
func main() {
contador := 1
// Esto equivale a: while (contador < 100)
for contador < 100 {
contador *= 2
fmt.Println("El contador es ahora:", contador)
}
}No hace falta una palabra clave nueva: si solo escribimos una condición, se comporta como un while.
El bucle infinito
¿Y si queremos un bucle que no termine nunca (o hasta que nosotros lo paremos manualmente)? Es el típico caso de un servidor web escuchando peticiones o un juego en su game loop.
En Go, eliminamos todo.
func main() {
for {
fmt.Println("¡Esto no para nunca!")
// Necesitaremos un mecanismo para salir, o Ctrl+C
}
}Esta es la forma canónica de hacer un while(true) en Go.
Control del bucle con break y continue
Al igual que en otros lenguajes, tenemos dos palabras clave para alterar el flujo normal dentro de un bucle:
- break: Rompe el bucle inmediatamente y sale de él.
- continue: Salta la iteración actual y pasa directamente a la siguiente (ejecutando el paso “post” si es un
forclásico).
Ejemplo con break
Buscamos un número y queremos parar en cuanto lo encontremos.
for i := 0; i < 10; i++ {
if i == 5 {
fmt.Println("¡Encontrado el 5! Nos vamos.")
break // Sale del for inmediatamente
}
fmt.Println("Buscando...", i)
}Ejemplo con continue
Queremos imprimir solo los números impares.
for i := 0; i < 5; i++ {
if i%2 == 0 {
continue // Es par, saltamos esta vuelta
}
fmt.Println("Impar:", i)
}Etiquetas en bucles anidados
Esto es algo que no se ve todos los días, pero es muy útil cuando trabajamos con algoritmos complejos. Si tienes un bucle dentro de otro bucle y quieres hacer un break que salga de ambos, puedes usar etiquetas.
func main() {
// Definimos una etiqueta llamada "BuclePrincipal"
BuclePrincipal:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Println(i, j)
if i == 1 && j == 1 {
fmt.Println("¡Rompiendo todo!")
break BuclePrincipal // Rompe el bucle externo etiquetado
}
}
}
fmt.Println("Fin del programa")
}Sin la etiqueta, el break solo saldría del bucle interno (j), y el externo (i) seguiría ejecutándose.
Iteración de colecciones
Aunque dedicaremos un artículo entero a las colecciones, es imposible hablar de for sin mencionar brevemente la cláusula range. Es el equivalente al foreach de C# o for..of de JS.
nombres := []string{"Luis", "Juan", "Ana"}
for indice, valor := range nombres {
fmt.Printf("Posición %d: %s\n", indice, valor)
}Esto lo veremos en profundidad cuando hablemos de arrays y slices.