¿Por qué es tan popular la pregunta "Is there a way to iterate over a range of integers?"
\n\nSi alguna vez has llegado a Go desde Python, seguramente recuerdas el elegante for i in range(10):. En Python funciona como un reloj. En Go... es un poco diferente. La pregunta en Stack Overflow con ese título ha acumulado miles de visitas, y no es casualidad. Los desarrolladores acostumbrados a abstracciones de alto nivel a menudo se pierden cuando se enfrentan a la sintaxis minimalista de Go.
En este artículo, analizaremos todas las formas de iterar sobre un rango de números enteros en Go: desde el clásico for hasta utilidades modernas. Aprenderás qué enfoque elegir para máximo rendimiento y cuál para la legibilidad del código. ¡Vamos allá!
Método n.º 1: For clásico (Go idiomático)
\n\nGo es un lenguaje de pragmáticos. No tiene un range incorporado para números, pero tiene un potente for. La forma más simple y eficiente es usar el bucle de tres componentes:
package main\n\nimport "fmt"\n\nfunc main() {\n // Iteración de 0 a 9 (10 elementos en total)\n for i := 0; i < 10; i++ {\n fmt.Println(i)\n }\n}\n\nEste código es máximamente eficiente: el compilador lo convierte en un simple incremento de registro. Sin asignaciones de memoria, sin sobrecarga. Así es como escriben los desarrolladores de Go en producción.
\n\nVariaciones del for clásico
\n\nPuedes cambiar fácilmente el valor inicial y el paso:
\n\n// De 5 a 15\nfor i := 5; i <= 15; i++ {\n fmt.Println(i)\n}\n\n// Solo números pares de 0 a 20\nfor i := 0; i <= 20; i += 2 {\n fmt.Println(i)\n}\n\n// Orden inverso: de 10 a 1\nfor i := 10; i >= 1; i-- {\n fmt.Println(i)\n}\n\nEste enfoque es el estándar de oro para iterar sobre un rango de números en Go. Es simple, claro y no requiere importar paquetes adicionales.
\n\nMétodo n.º 2: Usar range con un slice (para amantes de Python)
\n\nSi extrañas mucho el estilo de Python, puedes crear un slice y recorrerlo con range. Pero ten cuidado: esto afecta significativamente el rendimiento.
package main\n\nimport "fmt"\n\nfunc main() {\n // Creamos un slice de números del 0 al 9\n numbers := make([]int, 10)\n for i := range numbers {\n numbers[i] = i\n }\n\n // Ahora usamos range para iterar\n for _, num := range numbers {\n fmt.Println(num)\n }\n}\n\n¿Por qué es malo? Asignación de memoria. Cada vez que creas un slice, Go asigna memoria en el heap. Para un rango de 10 elementos es imperceptible, pero para 10 millones ya es un problema.
\n\nBenchmark: for vs range con slice
\n\nVeamos los números (iteración de 1 000 000 de números):
\n\n- \n
- For clásico: ~2.5 ms, 0 asignaciones \n
- Range con slice: ~45 ms, 1 asignación (8 MB) \n
¡Una diferencia de 18 veces! Y esto solo para un millón de elementos. Para rangos más grandes, la brecha solo aumenta.
\n\nMétodo n.º 3: Uso de bibliotecas (iter, lo, y otras)
\n\nLa comunidad de Go no se queda quieta. Existen bibliotecas de terceros que añaden azúcar sintáctico para iterar sobre rangos. Veamos dos populares:
\n\n3.1 Paquete iter (experimental, Go 1.23+)
\n\nA partir de Go 1.23, apareció en la biblioteca estándar el paquete experimental iter, que permite crear iteradores. Aún no es estable, pero ya está disponible:
package main\n\nimport (\n "fmt"\n "iter"\n)\n\nfunc main() {\n // Creamos un iterador de 0 a 9\n seq := iter.Seq[int](func(yield func(int) bool) {\n for i := 0; i < 10; i++ {\n if !yield(i) {\n return\n }\n }\n })\n\n for num := range seq {\n fmt.Println(num)\n }\n}