Introducción
En programación de computadoras, un ciclo es una estructura de código que se repite para ejecutar una porción de código repetidamente, generalmente hasta que se cumpla alguna condición específica. El uso de bucles en el lenguaje de programación de la computadora Go permite automatizar y repetir tareas similares múltiples veces. Imagina si tenías una lista de archivos que necesitarías procesar o si querías contar el número de líneas en un artículo. Usarás un bucle en tu código para resolver problemas de ese tipo.
En Go, la construcción for
implementa la ejecución repetida de código basada en un contador o variable de bucle. A diferencia de otros lenguajes de programación que tienen varios constructos de bucle, como while
, do
, etc., Go solo tiene la construcción for
. Esto sirve para hacer más claro y legible tu código, ya que no tienes que preocuparte con varios estrategias para lograr el mismo objetivo de bucle. Este aumento en la legibilidad y la carga cognitiva durante el desarrollo también hará que tu código sea menos propenso a errores que en otros lenguajes.
En este tutorial, aprenderás cómo funciona el bucle for
en Go, incluyendo las tres principales variaciones de su uso. Comenzamos mostrando cómo crear diferentes tipos de bucles for
, seguidos de cómo iterar sobre tipos de datos secuenciales en Go. Concluiremos explicando cómo usar bucles anidados.
Declarando clausuras de for y bucles condicionales
Para contemplar una variedad de casos de uso, hay tres maneras distintas de crear bucles for
en Go, cada una con sus propias capacidades. Estas son la declaración de una clausura for, una cláusula for, o una cláusula range. En esta sección explicaremos cómo declarar y usar las variantes de clausura for y bucle condicional.
Vamos a examinar cómo podemos usar un bucle for
con la cláusula ForClause primero.
Una cláusula for está definida como tener una sentencia inicial, seguida por una condición, y luego una sentencia posterior. Estos están arrangidos en la siguiente sintaxis:
for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
[Action]
}
Para explicar qué cada componente hace, vamos a mirar un bucle que incrementa a través de un rango especificado de valores utilizando la sintaxis de la cláusula ForClause:
Veamos detalladamente cada parte de este bucle.
El primer elemento de la sentencia es i := 0
. Esta es la sentencia inicial:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
Lo que hace es declarar una variable llamada i
y asignarle el valor inicial de 0
.
Luego viene la condición:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
En esta condición, declaramos que mientras i
sea menor que el valor de 5
, el bucle debe continuar iterando.
Finalmente, tenemos la sentencia posterior:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
En la declaración de post, incrementamos la variable del bucle i
cada vez que ocurre una iteración utilizando el operador i++
.Aumentar cuando ejecutemos este programa, la salida se ve así:
El bucle se ejecutó 5 veces. Inicialmente, se estableció i
en 0
, y luego se verificó si i
era menor que 5
. Dado que el valor de i
era menor que 5
, el bucle se ejecutó y se ejecutó la acción de fmt.Println(i)
. Después de que terminó el bucle, se llamó al post de i++
, y el valor de i
fue incrementado por 1.
Output0
1
2
3
4
Tenemos en cuenta que en programación generalmente comenzamos con índice 0, por eso es que aunque se impriman 5 números, van desde 0 hasta 4.
Atención: Recuerda que no estamos limitados a comenzar en 0 o terminar en un valor específico. Puedes asignar cualquier valor a tu declaración inicial y también detenerse en cualquier valor en tu post declaración. Esto nos permite crear cualquier rango deseado para iterar:
Ahora, vamos a usar nuestra post declaración con un valor positivo:
En este caso, la iteración va de 20 (inclusiva) a 25 (excluida), por lo que la salida se ve así:
Output20
21
22
23
24
Podemos también usar nuestro post con un valor positivo diferente. Este es similar a step
en otros lenguajes:
Primero, vamos a usar una post declaración con un valor positivo:
for i := 0; i < 15; i += 3 {
fmt.Println(i)
}
En este caso, el bucle está configurado para que los números de 0 a 15 se impriman, pero con un incremento de 3, por lo que sólo se imprime cada tercer número, como sigue:
Output0
3
6
9
12
También podemos usar un valor negativo para nuestro argumento de la declaración posterior de la sentencia post. Pero tendríamos que ajustar adecuadamente los argumentos de la declaración inicial y condicional:
Aquí, establecemos i
con un valor inicial de 100
, utilizamos la condición de i < 0
para detenerse en 0
, y la declaración posterior decrementa el valor por 10 con el operador -=
. La bucle comienza en 100
y termina en 0
, disminuyendo por 10 con cada iteración. Podemos ver esto en la salida:
Output100
90
80
70
60
50
40
30
20
10
También puedes excluir la declaración inicial y la declaración posterior de la sintaxis for
y solo usar la cláusula condicional. Esto es lo que se conoce como una Loop condicional:
i := 0
for i < 5 {
fmt.Println(i)
i++
}
Esta vez, declaramos la variable i
separadamente de la sentencia for
en la línea de código anterior. La bucle solo tiene una cláusula condicional que comprueba si i
es menor que 5
. Mientras que la condición se evalúe como true
, la bucle continuará iterando.
Algunas veces podrías no saber cuántas iteraciones necesitarás para completar cierta tarea. En ese caso, puedes omitir todas las instrucciones y usar la palabra clave break
para salir de ejecución:
for {
if someCondition {
break
}
// hacer acción aquí
}
Un ejemplo de esto podría ser si estás leyendo desde una estructura indefinidamente grande como un buffer y no sabes cuándo terminarás de leer:
En el código precedente, buf :=bytes.NewBufferString("one\ntwo\nthree\nfour\n")
declara un buffer con algunos datos. Debido a que no sabemos cuando el buffer terminará de leer, creamos un for
con una condición. Dentro del for
bucle, utilizamos line, err := buf.ReadString('\n')
para leer una línea del buffer y comprobar si hubo un error al leer del buffer. Si hubo, abordamos el error, y usamos la palabra clave break
para salir del bucle for. Con estos break
puntos, no necesitas incluir una condición para detener el bucle.
En esta sección, aprendimos cómo declarar un bucle ForClause y usarlo para iterar a través de un rango conocido de valores. También aprendimos cómo usar un bucle Condición para iterar hasta que se cumpla una condición específica. A continuación, aprenderemos cómo se utiliza la cláusula RangeClause para iterar a través de tipos de datos secuenciales.
Iterar a través de tipos de datos secuenciales con RangeClause
Es común en Go utilizar bucles for
para iterar sobre los elementos de tipos de datos secuenciales o coleccionales como slices, arrays y strings. Para hacer esto más fácil, podemos usar un bucle for
con la sintaxis de RangeClause. Si bien se puede iterar a través de tipos de datos secuenciales usando la sintaxis ForClause, la RangeClause es más limpia y fácil de leer.
Antes de mirar cómo usar la RangeClause, vamos a ver cómo podemos iterar a través de un slice usando la sintaxis ForClause:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for i := 0; i < len(sharks); i++ {
fmt.Println(sharks[i])
}
}
Ejecutar esto dará el siguiente resultado, imprimiendo cada elemento del slice:
Outputhammerhead
great white
dogfish
frilled
bullhead
requiem
Ahora, vamos a usar la RangeClause para realizar el mismo conjunto de acciones:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for i, shark := range sharks {
fmt.Println(i, shark)
}
}
En este caso, estamos imprimiendo cada elemento en la lista. Aunque usamos las variables i
y shark
, podríamos haber llamado a la variable cualquier otro nombre de variable válido y obtendríamos el mismo resultado:
Output0 hammerhead
1 great white
2 dogfish
3 frilled
4 bullhead
5 requiem
Cuando se usa range
en un slice, siempre devuelve dos valores. El primer valor será el índice en el que se encuentra la iteración actual del bucle, y el segundo es el valor en esa posición. En este caso, para la primera iteración, el índice fue 0
, y el valor fue hammerhead
.
Algunas veces solo queremos el valor dentro de los elementos de la cadena de caracteres, no el índice. Si cambiamos el código previo para imprimir sólo el valor sin embargo, recibirá un error de compilación:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for i, shark := range sharks {
fmt.Println(shark)
}
}
Outputsrc/range-error.go:8:6: i declared and not used
Porque i se declara en el bucle for, pero nunca se utiliza, el compilador responderá con el error de i declarado y no usado. Esto es lo mismo que recibirás en Go cualquier vez que declares una variable y no la uses.
Debido a esto, Go tiene el identificador vacío que es una comilla baja (_
). En un bucle for
, puedes usar el identificador vacío para ignorar cualquier valor retornado por la palabra clave range
. En este caso, querremos ignorar el índice, el primer argumento retornado.
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for _, shark := range sharks {
fmt.Println(shark)
}
}
Outputhammerhead
great white
dogfish
frilled
bullhead
requiem
Esto muestra que el bucle for
iteró sobre la cadena de caracteres de enteros y imprimió cada elemento de la cadena sin el índice.
También puedes usar range
para agregar elementos a una lista:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for range sharks {
sharks = append(sharks, "shark")
}
fmt.Printf("%q\n", sharks)
}
Output['hammerhead', 'great white', 'dogfish', 'frilled', 'bullhead', 'requiem', 'shark', 'shark', 'shark', 'shark', 'shark', 'shark']
Aquí, hemos agregado una cadena de lugares de sustitución de "shark"
para cada elemento de la longitud de la sharks
cadena.
Notice que no tenemos que usar el identificador vacío _
para ignorar cualquiera de los valores devueltos por la operadora range
. Go permite dejar fuera completamente la declaración de la parte de la range
si no necesitas usar ninguno de los valores devueltos.
Puedes también usar la operadora range
para llenar valores de una lista:
package main
import "fmt"
func main() {
integers := make([]int, 10)
fmt.Println(integers)
for i := range integers {
integers[i] = i
}
fmt.Println(integers)
}
En este ejemplo, la sección
Output[0 0 0 0 0 0 0 0 0 0]
[0 1 2 3 4 5 6 7 8 9]
La primera vez que imprimimos el valor de la sección
También podemos usar el operador
OutputS
a
m
m
y
Cuando iteramos sobre un map,
Outputcolor: blue
location: ocean
name: Sammy
animal: shark
Notas:Es importante recordar que la orden en la que un mapa te devuelve es aleatoria. Cada vez que ejecutes este programa puedes obtener un resultado diferente.
Ahora que hemos aprendido cómo iterar sobre datos secuenciales con
Bucle Anidado
Los bucles pueden estar anidados en Go, al igual que en otros lenguajes de programación. La anidación se refiere a que tenemos un constructor dentro de otro. En este caso, un bucle anidado es un bucle que se produce dentro de otro bucle. Estos pueden ser útiles cuando deseamos que una acción bucle sea ejecutada en cada elemento de un conjunto de datos.
Los bucles anidados son estructuralmente similares a declaraciones if
anidadas. Se construyen de la siguiente manera:
for {
[Action]
for {
[Action]
}
}
El programa primero encuentra el bucle externo, ejecutando su primera iteración. Esta primera iteración dispara el bucle interno anidado, que luego se ejecuta hasta su finalización. A continuación, el programa regresa a la parte superior del bucle externo, completando la segunda iteración y disparando nuevamente el bucle anidado. De nuevo, el bucle anidado se ejecuta hasta su finalización, y el programa regresa a la parte superior del bucle externo hasta que la secuencia esté completa o un break u otra declaración interrumpan el proceso.
Veamos cómo implementar un bucle for
anidado para echar un vistazo más de cerca. En este ejemplo, el bucle externo iterará a través de una secuencia de enteros llamada numList
, y el bucle interno iterará a través de una secuencia de cadenas llamada alphaList
.
Cuando ejecutamos este programa, obtendremos la siguiente salida:
Output1
a
b
c
2
a
b
c
3
a
b
c
La salida muestra que el programa completa la primera iteración de la bucle externo imprimiendo 1
, lo cual luego dispara la finalización de la bucle interna, imprimiendo a
, b
, c
consecutivamente. Una vez que la bucle interior haya terminado, el programa regresa al comienzo de la bucle exterior, imprime 2
, entonces nuevamente imprime la bucle interior completamente (a
, b
, c
), etc.
Las bucles for
anidadas pueden ser útiles para iterar sobre elementos dentro de las listas compuestas de listas. En un caso donde usemos solo una bucle for
, el programa se ejecutará como si fuera una sola lista:
Output[0 1 2]
[-1 -2 -3]
[9 8 7]
Para acceder a cada elemento de las listas internas, implementaremos una bucle anidada:
Output0
1
2
-1
-2
-3
9
8
7
Cuando utilicemos aquí una bucle anidada, podremos iterar sobre los elementos individuales contenidos en las listas internas.
Conclusión
En este tutorial hemos aprendido cómo declarar y usar las bucles for
para resolver tareas repetidas en Go. También hemos aprendido las tres variaciones diferentes de una bucle for
y cuándo usarlas. Para conocer más acerca de las bucles for
y cómo controlar el flujo de ellas, lea Using Break and Continue Statements When Working with Loops in Go.
Source:
https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-go