Existe um loop foreach no Go?

566

Existe uma foreachconstrução no idioma Go? Posso iterar sobre uma fatia ou matriz usando a for?

tatsuhirosatou
fonte
2
O uso de rangeem forlaços também é mencionada na secção "um interlúdio sobre tipos de" seção (para o seu fim) do tutorial Go.
Kostix 16/10/11

Respostas:

851

https://golang.org/ref/spec#For_range

Uma instrução "for" com uma cláusula "range" interage com todas as entradas de uma matriz, fatia, string ou mapa ou valores recebidos em um canal. Para cada entrada, atribui valores de iteração às variáveis ​​de iteração correspondentes e, em seguida, executa o bloco.

Como um exemplo:

for index, element := range someSlice {
    // index is the index where we are
    // element is the element from someSlice for where we are
}

Se você não se importa com o índice, pode usar _:

for _, element := range someSlice {
    // element is the element from someSlice for where we are
}

O sublinhado,, _é o identificador em branco , um espaço reservado anônimo.

davetron5000
fonte
7
Neste exemplo, elementé o valor do elemento (uma cópia) - não é o próprio elemento. Embora você possa atribuir a element, isso não afetará a sequência subjacente.
Nobar
Eu sei que em Python e C é frequente usar sublinhado como uma função para localização (ou seja, o gettext ). O uso de sublinhado causaria problemas no Go? O Go usa a mesma biblioteca para localização?
Sergiy Kolodyazhnyy
3
O @SergiyKolodyazhnyy Py docs diz que "a função (gettext) geralmente é apelidada como _()no espaço de nomes local", que é apenas por convenção , não faz parte da biblioteca de localização. O sublinhado _é um rótulo válido e também é uma convenção no Go (e Python e Scala e outros idiomas) para atribuir _valores retornados aos quais você não usará. O escopo _deste exemplo é restrito ao corpo do forloop. Se você tiver uma função com escopo definido no pacote _, ela estará sombreada no escopo do loop for. Existem alguns pacotes para localização, não vi nenhum uso _como nome de função.
Davos
150

Go tem uma foreachsintaxe parecida. Ele suporta matrizes / fatias, mapas e canais.

Iterar sobre matriz ou fatia :

// index and value
for i, v := range slice {}

// index only
for i := range slice {}

// value only
for _, v := range slice {}

Iterar sobre um mapa :

// key and value
for key, value := range theMap {}

// key only
for key := range theMap {}

// value only
for _, value := range theMap {}

Iterar sobre um canal :

for v := range theChan {}

A iteração sobre um canal é equivalente a receber de um canal até que ele seja fechado:

for {
    v, ok := <-theChan
    if !ok {
        break
    }
}
Moshe Revah
fonte
11
Embora o OP tenha solicitado apenas o uso de fatia, prefiro essa resposta, porque a maioria também precisará dos outros usos.
domoarigato 2/08/16
3
distinção importante sobre o chanuso: percorrer um canal sairá graciosamente do loop se o gravador fechar o canal em algum momento. No for {v := <-theChan} equivalente , ele não sai no canal fechado. Você pode testar isso através do segundo okvalor de retorno. EXEMPLO DE TOUR
colm.anseo 10/10
Pensou o mesmo ao lê-lo, for { ... }significa um loop infinito.
Levite
13

O exemplo a seguir mostra como usar o rangeoperador em um forloop para implementar um foreachloop.

func PrintXml (out io.Writer, value interface{}) error {
    var data []byte
    var err error

    for _, action := range []func() {
        func () { data, err = xml.MarshalIndent(value, "", "  ") },
        func () { _, err = out.Write([]byte(xml.Header)) },
        func () { _, err = out.Write(data) },
        func () { _, err = out.Write([]byte("\n")) }} {
        action();
        if err != nil {
            return err
        }
    }
    return nil;
}

O exemplo itera sobre uma matriz de funções para unificar o tratamento de erros para as funções. Um exemplo completo está no playground do Google .

PS: mostra também que suspensórios são uma má idéia para a legibilidade do código. Dica: a forcondição termina logo antes da action()chamada. Óbvio, não é?

ceving
fonte
3
Adicione um ,e fique mais claro onde a forcondição termina: play.golang.org/p/pcRg6WdxBd - Essa é a primeira vez que encontrei um contra-argumento para o go fmtestilo, obrigado!
Top742
@topskip ambos são válidos para fmt; apenas escolher o melhor :)
Filip Haglund
@FilipHaglund Não é o ponto se é válido. O ponto é que, na IMO, é mais claro onde a condição for termina nesse caso específico acima.
topskip
9
Na minha opinião, esta resposta é irracionalmente complexa para a pergunta direcionada.
precisa
@AndreasHassing Como fazer isso sem introduzir redundância?
ceving 16/01/19
10

De fato, você pode usar rangesem referenciar seus valores de retorno usando for rangecontra o seu tipo:

arr := make([]uint8, 5)
i,j := 0,0
for range arr {
    fmt.Println("Array Loop",i)
    i++
}

for range "bytes" {
    fmt.Println("String Loop",j)
    j++
}

https://play.golang.org/p/XHrHLbJMEd

robstarbuck
fonte
3
É bom saber, mas que não vai ser útil na maioria dos casos
Sridhar
@Sridhar concordou que é muito nicho.
robstarbuck 5/09/16
10

A seguir está o código de exemplo de como usar o foreach no golang

package main

import (
    "fmt"
)

func main() {

    arrayOne := [3]string{"Apple", "Mango", "Banana"}

    for index,element := range arrayOne{

        fmt.Println(index)
        fmt.Println(element)        

    }   

}

Este é um exemplo em execução https://play.golang.org/p/LXptmH4X_0

Nisal Edu
fonte
muito boa explicação!
Darlan Dieterich 03/03
Às vezes, é o exemplo mais simples que é o mais útil. Obrigado! Não tenho nada contra as respostas mais esotéricas dos outros comentaristas - eles certamente ilustram os meandros da programação Go muito idiomática, a ponto de se tornarem ... ilegíveis e difíceis de seguir - mas prefiro sua resposta: ela segue em frente até o núcleo com o exemplo mais simples possível (que funciona e é óbvio por que funciona).
Gwyneth Llewelyn
4

Sim, intervalo :

A forma de intervalo do loop for itera sobre uma fatia ou mapa.

Ao ultrapassar uma fatia, dois valores são retornados para cada iteração. O primeiro é o índice e o segundo é uma cópia do elemento nesse índice.

Exemplo:

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    for i, v := range pow {
        fmt.Printf("2**%d = %d\n", i, v)
    }

    for i := range pow {
        pow[i] = 1 << uint(i) // == 2**i
    }
    for _, value := range pow {
        fmt.Printf("%d\n", value)
    }
}
  • Você pode pular o índice ou valor atribuindo a _.
  • Se você deseja apenas o índice, solte o valor, inteiramente.
Amitesh
fonte
1

Isso pode ser óbvio, mas você pode incorporar a matriz da seguinte maneira:

package main

import (
    "fmt"
)

func main() {
    for _, element := range [3]string{"a", "b", "c"} {
        fmt.Print(element)
    }
}

saídas:

abc

https://play.golang.org/p/gkKgF3y5nmt

jpihl
fonte