El bucle for tradicional en Go constituye el único mecanismo de iteración del lenguaje, empleando la estructura de tres componentes init; condition; post heredada de la familia de lenguajes C. A diferencia de otros lenguajes que separan la iteración por contador de la iteración condicional (usando while), Go unifica ambos comportamientos bajo una misma palabra reservada, variando únicamente la presencia o ausencia de sus cláusulas delimitadas por puntos y coma.
Este diseño simplificado elimina la redundancia en la gramática del compilador y reduce la carga cognitiva del desarrollador. Al no existir la sentencia while, se estandariza el control de flujo iterativo, forzando a que cualquier patrón de repetición se resuelva mediante la versatilidad de for. Esta decisión arquitectónica favorece la legibilidad, ya que la gestión del estado de la iteración se mantiene concentrada en la cabecera del bucle, evitando que la lógica de actualización se pierda entre las líneas del cuerpo del bloque.
La instrucción se descompone en tres segmentos técnicos bien definidos. La sentencia de inicialización (init) se ejecuta exactamente una vez antes de la primera evaluación. Generalmente, se utiliza para una declaración corta de variables (:=), lo cual crea un nuevo ámbito o scope léxico específico para el bucle. La condición se evalúa antes de cada iteración; si el resultado booleano es false, el bucle termina. Finalmente, la sentencia posterior (post) se ejecuta inmediatamente después de cada iteración del cuerpo y antes de la siguiente evaluación de la condición. Es importante notar que, en Go, las tres partes son opcionales.
package main
import "fmt"
func main() {
// Variante completa: init; condition; post
for i := 0; i < 3; i++ {
fmt.Printf("Iteración: %d\n", i)
}
// Variante omitiendo init y post (comportamiento de 'while')
count := 0
for count < 2 {
fmt.Printf("Contador manual: %d\n", count)
count++
}
// Variante omitiendo condition (bucle infinito)
for i := 0; ; i++ {
if i > 1 {
break // Salida manual
}
fmt.Println("Bucle con salida controlada")
}
}
/* Output:
Iteración: 0
Iteración: 1
Iteración: 2
Contador manual: 0
Contador manual: 1
Bucle con salida controlada
Bucle con salida controlada
*/
GoUna característica que diferencia a Go de C es que la sentencia post no puede ser una expresión que devuelva un valor, sino que debe ser una sentencia simple. Esto impide construcciones confusas donde se intenta asignar y evaluar simultáneamente dentro de la cláusula de actualización, manteniendo la claridad del flujo.
La visibilidad léxica y la persistencia de la cláusula post
Un aspecto crítico del funcionamiento interno del bucle for tradicional es el ciclo de vida de las variables declaradas en la sección init. Estas variables no solo son visibles en el cuerpo del bucle, sino que también están disponibles dentro de las secciones de condición y post. Sin embargo, su scope queda restringido exclusivamente a la estructura del for. Intentar acceder a la variable de control después de que las llaves de cierre han sido alcanzadas provocará un error de “undefined variable” durante la compilación.
func scopeDemonstration() {
for i := 0; i < 5; i++ {
// 'i' es accesible aquí
}
// fmt.Println(i) // Error de compilación: undefined: i
}
GoEl edge case más relevante ocurre cuando se utiliza continue. Al invocar continue, el runtime salta el resto del código en el cuerpo del bucle, pero la cláusula post se ejecuta obligatoriamente antes de volver a evaluar la condición. Esto garantiza que los contadores se actualicen de forma determinista, evitando bucles infinitos accidentales que suelen ocurrir en implementaciones manuales donde la actualización del estado queda atrapada después de una sentencia de salto.
- Módulo: Control de Flujo
- Artículo número: #53