Em Go, o for range repete um bloco de código para valores de uma expressão de range.
A expressão de range determina se cada iteração vai devolver um valor ou dois.
O range sobre um slice devolve o índice e o valor de cada elemento, por ordem:
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(i, v)
}
// 0 10
// 1 20
// 2 30
O range sobre um map devolve cada chave e valor, mas a ordem de iteração não é garantida.
O Go randomiza deliberadamente a ordem de iteração dos maps, por isso o mesmo programa pode produzir resultados diferentes em cada execução.
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// 99 20
// 999 30
// 9 10
O range sobre uma string devolve o índice em bytes e cada rune (ponto de código Unicode).
No exemplo seguinte, o 子 ocupa três bytes, por isso o 猫 começa no índice de byte 3 e não em 1.
for i, r := range "子猫" {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 3 29483 猫
Se precisares de índices de runes, converte a string num slice de runes:
for i, r := range []rune("子猫") {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 1 29483 猫
O range pode iterar diretamente sobre um número inteiro, devolvendo valores desde 0 até esse número inteiro, sem o incluir.
Os valores zero e negativos são válidos, mas não produzem nenhuma iteração.
for n := range 3 {
fmt.Println(n)
}
// 0
// 1
// 2
O range aceita um iterador do tipo iter.Seq[V] ou iter.Seq2[K, V].
Um iterador é uma função que produz uma sequência de valores, um de cada vez.
O range pode então percorrer esses valores.
text := "The quick brown fox"
for word := range strings.FieldsSeq(text) {
fmt.Println(word)
}
// The
// quick
// brown
// fox
names := []string{"Alice", "Bob", "Vera"}
for i, v := range slices.All(names) {
fmt.Println(i, ":", v)
}
// 0 : Alice
// 1 : Bob
// 2 : Vera
Por fim, o range pode receber valores enviados através de um canal até que esse canal seja fechado noutro sítio.
Os canais são abordados com mais profundidade mais à frente no plano de estudos do percurso.
O Go não compila se uma variável for declarada mas nunca usada.
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(v)
}
// Go build failed: declared and not used: i
Se só precisares do valor, atribui o índice ou a chave a _ para o ignorar.
vals := []int{10, 20, 30}
for _, v := range vals {
fmt.Println(v)
}
// 10
// 20
// 30
Se só precisares do índice, omite-o completamente:
vals := []int{10, 20, 30}
for i := range vals {
fmt.Println(i)
}
// 0
// 1
// 2
Se não precisares nem do índice nem do valor, podes omitir ambos:
vals := []int{10, 20, 30}
count := 0
for range vals {
count++
}
// count == 3