Introdução
Na programação de computadores, uma estrutura de loop é uma estrutura de código que repete a execução de um pedaço de código, frequentemente até que alguma condição seja atingida. O uso de loops na programação de computadores permite automatizar e repetir tarefas semelhantes várias vezes. Imagine se você tivesse uma lista de arquivos que precisasse ser processada, ou se quisesse contar o número de linhas em um artigo. Você usaria um loop em seu código para resolver esses tipos de problemas.
Em Go, um loop for
implementa a execução repetida de código com base em um contador de loop ou variável de loop. Ao contrário de outras linguagens de programação que têm múltiplos construtos de loop, como while
, do
, etc., Go apenas tem o loop for
. Isto serve para tornar seu código mais claro e legível, já que você não precisa se preocupar com múltiplas estratégias para alcançar o mesmo construto de loop. Esta melhora na legibilidade e redução no carga cognitiva durante o desenvolvimento também tornará seu código menos propenso a erros do que em outras linguagens.
Neste tutorial, você vai aprender como o loop for
em Go funciona, incluindo as três variantes principais de seu uso. Vamos começar mostrando como criar diferentes tipos de loops for
, seguido de como percorrer tipos de dados seqüencias em Go. Concluiremos explicando como usar loops aninhados.
Declaração de Laços For e Condição
Para atender a uma variedade de casos de uso, existem três maneiras distintas de criar laços for
em Go, cada uma com suas próprias capacidades. São elas: criar um laço for
com uma Condição, uma ForClause ou uma RangeClause. Nesta seção, vamos explicar como declarar e usar as variantes ForClause e Condição.
Vamos primeiro olhar como podemos usar um laço for
com a ForClause.
Um laço ForClause é definido como tendo uma declaração inicial, seguida por uma condição e depois por uma declaração pós-laço. Estes estão arranjados na seguinte sintaxe:
for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
[Action]
}
Para explicar o que os componentes anteriores fazem, vamos olhar para um laço for
que incrementa através de um intervalo de valores especificado usando a sintaxe ForClause:
Vamos desconstruir este laço e identificar cada parte.
A primeira parte do laço é i := 0
. Esta é a declaração inicial:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
Ela afirma que estamos declarando uma variável chamada i
e definindo o valor inicial como 0
.
A próxima é a condição:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
Nesta condição, declaramos que enquanto i
for menor que o valor de 5
, o laço deve continuar executando.
Finalmente, temos a declaração pós-laço:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
No encadeamento de instruções, incrementamos a variável de loop i
em uma unidade a cada iteração usando o operador de incremento i++
.
Quando executamos este programa, a saída parece assim:
Output0
1
2
3
4
O loop executou 5 vezes. Inicialmente, ela definiu i
para 0
, e então verificou se i
era menor que 5
. Como o valor de i
era menor que 5
, o loop executou e a ação de fmt.Println(i)
foi executada. Após o fim do loop, a declaração de pós-execução de i++
foi chamada, e o valor de i
foi incrementado em 1.
Nota: Lembre-se que, em programação, tendemos a começar em 0, por isso é que embora 5 números sejam impressos, eles variam de 0 a 4.
Nós não estamos limitados a começar em 0 ou a terminar em um valor específico. Podemos atribuir qualquer valor à nossa declaração inicial e também parar em qualquer valor na declaração de pós-execução. Isso permite que criemos qualquer intervalo desejado para percorrer:
Aqui, a iteração vai de 20 (inclusivo) até 25 (exclusivo), portanto, a saída parece assim:
Output20
21
22
23
24
Também podemos usar nossa declaração de pós-execução para incrementar em valores diferentes. Isto é semelhante ao passo
em outras linguagens:
Primeiro, vamos usar uma declaração de pós-execução com um valor positivo:
for i := 0; i < 15; i += 3 {
fmt.Println(i)
}
Neste caso, o laço for
está configurado para que os números de 0 a 15 sejam impressos, mas com um incremento de 3, portanto, apenas cada terceiro número é impresso, como está aqui:
Output0
3
6
9
12
Nós também podemos usar um valor negativo para nosso argumento de declaração posterior na estrutura de repetição, mas terão que ajustar os argumentos iniciais e condicionais adequadamente:
Aqui, definimos i
com um valor inicial de 100
, usamos a condição de i < 0
para parar em 0
, e a declaração posterior decrementa o valor por 10 com o operador -=
. A loop começa em 100
e termina em 0
, diminuindo por 10 com cada iteração. Podemos ver isso no output:
Output100
90
80
70
60
50
40
30
20
10
Você pode excluir a declaração inicial e a declaração posterior da sintaxe for
e usar apenas a clausula condicional. Isso é conhecido como um Loop Condicional:
i := 0
for i < 5 {
fmt.Println(i)
i++
}
Estevemos declarando a variável i
separadamente da última linha de código do loop anterior. Agora, a loop tem uma clausula condicional que checa se i
é menor que 5
. Se a condição avalia para true
, o loop continuará a executar.
Algumas vezes você pode não saber quantas iterações você precisará para completar uma tarefa determinada. Nesse caso, você pode omitir todas as instruções e usar o operador break
para sair da execução:
for {
if someCondition {
break
}
// fazer ação aqui
}
Um exemplo disso pode ser se você está lendo de uma estrutura indefinida como um buffer e não saber quando terminará de ler:
Na código anterior, buf := bytes.NewBufferString("one
declara um buffer com algum dado. Porque não sabemos quando o buffer irá terminar de ler, nós criamos um laço
two
three
four
")for
sem clausula. Dentro do laço for
, usamos line, err = buf.ReadString
para ler uma linha do buffer e verificar se houve erro ao ler o buffer. Se houver um erro, tratamos o erro, e usamos o operador
")break
para sair do laço for
. Com esses pontos de break, você não precisa incluir uma condição para parar o laço. Neste trecho, aprendemos como declarar um ForClause loop e usar-lo para iterar sobre um rango conhecido de valores. Também aprendemos como usar um LoopCondition para iterar até que uma condição específica fosse satisfeita. A seguir, vamos aprender como o RangeClause é usado para iterar sobre tipos de dados seqüenciais.
Looping Through Sequential Data Types with RangeClause
Looping Through Sequential Data Types with RangeClause
É comum em Go usar laços for
para iterar sobre os elementos de tipos de dados sequenciais ou de coleções, como fatias, arrays e strings. Para fazer isso mais facilmente, podemos usar um laço for
com a sintaxe de RangeClause. Embora você consiga iterar por meio de tipos de dados sequenciais usando a sintaxe ForClause, a RangeClause é mais limpa e fácil de ler.
Antes de olharmos para o uso da RangeClause, vamos ver como podemos iterar por meio de uma fatia usando a sintaxe 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])
}
}
Executando isso dá o seguinte resultado, imprimindo cada elemento da fatia:
Outputhammerhead
great white
dogfish
frilled
bullhead
requiem
Agora, vamos usar a RangeClause para executar o mesmo conjunto de ações:
package main
import "fmt"
func main() {
sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}
for i, shark := range sharks {
fmt.Println(i, shark)
}
}
Neste caso, estamos imprimindo cada item na lista. Embora usamos as variáveis i
e shark
, poderíamos ter chamado a variável de qualquer outro nome de variável válido e obteríamos o mesmo resultado:
Output0 hammerhead
1 great white
2 dogfish
3 frilled
4 bullhead
5 requiem
Quando usamos range
the slice, ele sempre retorna dois valores. O primeiro valor será o índice que a iteração atual do loop está em, e o segundo é o valor nessa posição. Neste caso, para a primeira iteração, o índice era 0
, e o valor era hammerhead
.
Ocasionalmente, queremos apenas o valor dentro dos elementos de uma fatia, não o índice. Se alterarmos o código anterior para imprimir somente o valor, receberão um erro de compilação:
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 é declarado no loop for, mas nunca usado, o compilador responderá com o erro de i declarado e não usado. Isso é o mesmo erro que você receberá em Go sempre que você declare uma variável e não use ela.
Por causa disso, Go tem o identificador vazio que é um sublinhamento (_
). Na for
loop, você pode usar o identificador vazio para ignorar qualquer valor retornado pelo operador range
. Neste caso, queremos ignorar o índice, que é a primeira 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
Esta saída mostra que o loop for
iterou sobre a fatia de strings e imprimiu cada item da fatia sem o índice.
Você também pode usar range
para adicionar itens à 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']
Aqui, nós adicionamos uma string de "shark"
para cada item do tamanho da fatia sharks
.
Observe que não houve necessidade de usar o identificador vazio _
para ignorar qualquer valor retornado do operador range
. O Go permite deixar o completo da declaração do range
ausente se não precisarmos usar nenhum dos valores retornados.
Podemos também usar o operador range
para preencher valores de uma fatia:
package main
import "fmt"
func main() {
integers := make([]int, 10)
fmt.Println(integers)
for i := range integers {
integers[i] = i
}
fmt.Println(integers)
}
Na primeira linha deste exemplo, o slice integers
é inicializado com dez valores vazios, mas a loop for
executa para cada índice do slice e define todos os valores na lista como se fossem assim:
Output[0 0 0 0 0 0 0 0 0 0]
[0 1 2 3 4 5 6 7 8 9]
A primeira vez que imprimimos o valor do slice integers
, vemos todos os zeros. Então, nós iteramos sobre cada índice e definimos o valor para a posição atual. Quando imprimimos o valor do integers
novamente, mostramos que eles agora tem um valor de 0
até 9
.
Podemos também usar o operador range
para iterar sobre cada caractere em uma string:
OutputS
a
m
m
y
Quando iterando sobre um map, range
retornará ambos o chave e o valor:
Outputcolor: blue
location: ocean
name: Sammy
animal: shark
Observação: É importante notar que a ordem em que um map retorna é aleatoria. Cada vez que você executar este programa, você pode obter um resultado diferente.
Agora que já conhecemos como iterar sobre dados seqüenciais com range
e for
loops, vamos ver como usar loops dentro de loops.
Loop Nested
As estruturas de loop podem ser aninhadas em Go, tal como podem ser em outras linguagens de programação. Aninhamento é quando temos um construto dentro de outro. Neste caso, uma estrutura de loop aninhada é um loop que ocorre dentro de outro loop. Estes podem ser úteis quando você gostaria de ter uma ação de loop realizada em cada elemento de um conjunto de dados.
As estruturas de loop aninhadas são estruturalmente semelhantes a declarações if
aninhadas. Eles são construídos da seguinte forma:
for {
[Action]
for {
[Action]
}
}
O programa primeiro encontra o loop externo, executando sua primeira iteração. Esta primeira iteração dispara o loop interno, aninhado, que então executa até o fim. Então o programa volta para o topo do loop externo, completando a segunda iteração e novamente disparando o loop aninhado. Novamente, o loop aninhado executa até o fim, e o programa volta para o topo do loop externo até que a sequência seja concluída ou um break ou outra declaração interrompa o processo.
Vamos implementar um loop for
aninhado para podermos olhar mais de perto. Neste exemplo, o loop externo vai iterar por um slice de inteiros chamado numList
, e o loop interno vai iterar por um slice de strings chamado alphaList
.
Quando executarmos este programa, receberá a seguinte saída:
Output1
a
b
c
2
a
b
c
3
a
b
c
A execução mostra que o programa completa a primeira iteração do loop externo imprimindo 1
, o que então dispara a conclusão do loop interno, imprimindo a
, b
, c
consecutivamente. Uma vez que o loop interno tenha sido completado, o programa retorna ao início do loop externo, imprime 2
, e então novamente imprime todo o loop interno (a
, b
, c
), etc.
Loopes aninhados de for
podem ser úteis para iterar sobre itens dentro de fatias compostas de fatias. Na ausência de um único loop for
, o programa irá exibir cada lista interna como um item:
Output[0 1 2]
[-1 -2 -3]
[9 8 7]
Para acessar cada item da lista interna, vamos implementar um loop aninhado:
Output0
1
2
-1
-2
-3
9
8
7
Quando usamos um loop aninhado aqui, estamos capazes de iterar sobre os itens contidos nas fatias internas.
Conclusão
Nesta introdução, aprendemos como declarar e usar laços for
para resolver tarefas repetidas em Go. Também lemos as três variantes diferentes de um laço for
e quando usar cada uma. Para saber mais sobre como trabalhar com laços for
e como controlar o fluxo deles, leia Usando Breaks e Continues Quando Trabalhando com Laços em Go.
Source:
https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-go