En esta página
Control de flujo
Control de flujo en Go: simplificado y potente
El control de flujo determina qué instrucciones se ejecutan, cuántas veces y bajo qué condiciones. Go toma decisiones de diseño deliberadas para simplificar las estructuras de control: hay un solo bucle (for), los if no tienen paréntesis, y el switch no necesita break. Menos sintaxis, menos errores.
`if` y `else`: sin paréntesis
La primera diferencia que notarás si vienes de C, Java o JavaScript es que las condiciones en Go no llevan paréntesis. Las llaves {} son obligatorias siempre — Go no permite el formato de una sola línea sin llaves:
temperatura := 25
if temperatura > 30 {
fmt.Println("Hace calor")
} else if temperatura > 20 {
fmt.Println("Temperatura agradable")
} else {
fmt.Println("Hace frío")
}La declaración de inicialización del `if`
Go permite declarar una variable dentro del if que solo existe en el scope del bloque if/else. Este patrón es muy común cuando el resultado de una operación solo importa dentro del condicional:
// n solo existe dentro del if/else
if n := calcularValor(); n > 100 {
fmt.Println("Valor alto:", n)
} else {
fmt.Println("Valor normal:", n)
}
// n no existe aquí
// Patrón muy común con errores
if err := hacerAlgo(); err != nil {
fmt.Println("Error:", err)
return
}Este patrón mantiene el código limpio: la variable está disponible exactamente donde se necesita y no contamina el scope circundante.
`switch`: elegante y sin bugs de fallthrough
El switch de Go es más poderoso y seguro que el de C o Java:
Switch básico
día := 3 // Miércoles
switch día {
case 1:
fmt.Println("Lunes")
case 2:
fmt.Println("Martes")
case 3:
fmt.Println("Miércoles")
case 4:
fmt.Println("Jueves")
case 5:
fmt.Println("Viernes")
default:
fmt.Println("Fin de semana")
}Múltiples valores por caso
switch día {
case 1, 2, 3, 4, 5:
fmt.Println("Día hábil")
case 6, 7:
fmt.Println("Fin de semana")
}Switch sin expresión (como un if-else-if)
Cuando no provees una expresión de comparación, el switch evalúa condiciones booleanas en cada case:
hora := 14
switch {
case hora < 12:
fmt.Println("Buenos días")
case hora < 18:
fmt.Println("Buenas tardes")
default:
fmt.Println("Buenas noches")
}Switch con inicialización
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS")
case "linux":
fmt.Println("Linux")
default:
fmt.Printf("Otro: %s\n", os)
}`fallthrough` explícito
Si necesitas el comportamiento de caída, úsalo explícitamente:
n := 3
switch n {
case 3:
fmt.Println("Tres")
fallthrough // ejecuta el siguiente case también
case 2:
fmt.Println("Dos o más")
case 1:
fmt.Println("Uno")
}
// Imprime: Tres
// Dos o más`for`: el único bucle de Go
Go tomó la decisión radical de tener un único tipo de bucle: for. Pero for tiene múltiples formas que cubren todos los casos de uso.
Forma 1: Clásico (init; condition; post)
// Suma de 1 a 100
suma := 0
for i := 1; i <= 100; i++ {
suma += i
}
fmt.Println("Suma:", suma) // 5050
// Contar hacia atrás
for i := 10; i > 0; i-- {
fmt.Print(i, " ")
}
fmt.Println()
// Múltiples variables
for i, j := 0, 10; i < j; i, j = i+1, j-1 {
fmt.Printf("i=%d, j=%d\n", i, j)
}Forma 2: Condicional (equivalente a `while`)
// Leer input hasta que sea válido
entrada := 0
for entrada < 5 {
entrada++
fmt.Println("Procesando:", entrada)
}
// Bucle "while true" con break interno
intentos := 0
for {
intentos++
if intentos >= 3 {
break
}
}Forma 3: Bucle infinito
// Servidor que se ejecuta para siempre (común en goroutines)
for {
// procesar trabajo...
// usar break o return para salir
}`range`: iterar sobre colecciones
range es la forma idiomática de Go para iterar sobre arrays, slices, maps, strings y canales:
// Sobre un slice: índice y valor
números := []int{10, 20, 30, 40, 50}
for i, n := range números {
fmt.Printf("números[%d] = %d\n", i, n)
}
// Solo el índice
for i := range números {
fmt.Println(i)
}
// Solo el valor (descartar índice con _)
for _, n := range números {
fmt.Println(n)
}
// Sobre un map: clave y valor
capitales := map[string]string{
"Bolivia": "Sucre",
"Argentina": "Buenos Aires",
"Brasil": "Brasilia",
}
for país, capital := range capitales {
fmt.Printf("Capital de %s: %s\n", país, capital)
}
// Sobre un string: índice de byte y rune
for i, r := range "¡Hola!" {
fmt.Printf("índice: %d, carácter: %c\n", i, r)
}
// Go 1.22+: range sobre entero
for i := range 5 { // 0, 1, 2, 3, 4
fmt.Println(i)
}`break` y `continue`
// break: salir del bucle inmediatamente
for i := 0; i < 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
// Imprime: 0 1 2 3 4
// continue: saltar al siguiente ciclo
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // saltar números pares
}
fmt.Println(i)
}
// Imprime: 1 3 5 7 9Break etiquetado: salir de bucles anidados
En Go, puedes poner una etiqueta en un bucle y usarla con break o continue para controlar bucles externos. Esto evita la necesidad de variables de control adicionales:
// Sin etiquetas: necesitas una variable extra
encontrado := false
for i := 0; i < 5 && !encontrado; i++ {
for j := 0; j < 5; j++ {
if i*j > 6 {
encontrado = true
break
}
}
}
// Con etiquetas: más limpio
externo:
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
if i*j > 6 {
fmt.Printf("Encontrado en (%d, %d)\n", i, j)
break externo // sale de ambos bucles
}
}
}
// continue etiquetado
externo:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 1 {
continue externo // salta al siguiente i
}
fmt.Printf("(%d,%d) ", i, j)
}
}
// Imprime: (0,0) (1,0) (2,0)Resumen de patrones idiomáticos
| Patrón | Código |
|---|---|
| If con inicialización | if err := f(); err != nil { ... } |
| While | for condición { ... } |
| Infinito | for { ... } |
| For clásico | for i := 0; i < n; i++ { ... } |
| Iterar slice | for i, v := range slice { ... } |
| Iterar map | for k, v := range mapa { ... } |
| Salir de anidados | break etiqueta |
Con estas estructuras de control dominadas, en la próxima lección aprenderemos las funciones de Go: múltiples valores de retorno, funciones variádicas, closures y el poderoso defer.
Inicia sesión para guardar tu progreso