Esiste un ciclo foreach in Go?


Risposte:


851

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

Un'istruzione "for" con una clausola "range" scorre tutte le voci di un array, slice, stringa o mappa o valori ricevuti su un canale. Per ogni voce assegna i valori di iterazione alle corrispondenti variabili di iterazione e quindi esegue il blocco.

Come esempio:

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

Se non ti interessa l'indice, puoi utilizzare _:

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

Il trattino basso, _è l' identificatore vuoto , un segnaposto anonimo.


7
In questo esempio, elementè il valore dell'elemento (una copia) - non è l'elemento stesso. Sebbene sia possibile assegnare a element, ciò non influirà sulla sequenza sottostante.
nobar

So che in Python e C è frequente usare il trattino basso come funzione per la localizzazione (cioè il gettext ). L'uso del trattino basso potrebbe causare problemi in Go? Go utilizza anche la stessa libreria per la localizzazione?
Sergiy Kolodyazhnyy,

3
@SergiyKolodyazhnyy Py docs afferma che "la funzione (gettext) è di solito aliasata come _()nello spazio dei nomi locale" che è solo per convenzione , non fa parte della libreria di localizzazione. Il carattere di sottolineatura _è un'etichetta valida ed è anche una convenzione in Go (e Python, Scala e altre lingue) da assegnare _per i valori di ritorno che non verranno utilizzati. L'ambito di _questo esempio è limitato al corpo del forloop. Se si dispone di una funzione con ambito pacchetto _, verrebbe ombreggiata all'interno dell'ambito del ciclo for. Ci sono alcuni pacchetti per la localizzazione, non ho visto alcun uso _come nome di una funzione.
Davos,

150

Go ha una foreachsintassi simile. Supporta matrici / sezioni, mappe e canali.

Scorrere su array o slice :

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

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

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

Scorrere su una mappa :

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

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

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

Scorrere su un canale :

for v := range theChan {}

L'iterazione su un canale equivale alla ricezione da un canale fino alla sua chiusura:

for {
    v, ok := <-theChan
    if !ok {
        break
    }
}

11
Anche se l'OP ha chiesto solo l'uso della fetta, preferisco questa risposta, perché la maggior parte alla fine avrà bisogno anche degli altri usi.
domoarigato,

3
importante distinzione chansull'uso: andare su un canale uscirà con garbo dal ciclo se lo scrittore chiude il canale ad un certo punto. Nella for {v := <-theChan} equivalente , esso non esce sul canale vicino. È possibile verificare questo tramite il secondo okvalore restituito. ESEMPIO TOUR
colm.anseo,

Pensato lo stesso durante la lettura, for { ... }rappresenta un ciclo infinito.
Levita,

13

L'esempio seguente mostra come utilizzare l' rangeoperatore in un forciclo per implementare un foreachciclo.

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;
}

L'esempio scorre una serie di funzioni per unificare la gestione degli errori per le funzioni. Un esempio completo è nel parco giochi di Google .

PS: mostra anche che le parentesi graffe sospese sono una cattiva idea per la leggibilità del codice. Suggerimento: la forcondizione termina poco prima della action()chiamata. Ovvio, no?


3
Aggiungi a ,ed è più chiaro dove forfinisce la condizione: play.golang.org/p/pcRg6WdxBd - Questa è in realtà la prima volta che trovo un argomento contrario allo go fmtstile, grazie!
topskip

@topskip entrambi sono validi; scegli quello migliore :)
Filip Haglund,

@FilipHaglund Non è il punto se è valido. Il punto è che l'IMO è più chiaro dove finisce la condizione for in quel caso particolare sopra.
topskip

9
A mio avviso, questa risposta è irragionevolmente complessa per la domanda mirata.
AndreasHassing,

@AndreasHassing Come farlo invece senza introdurre ridondanza?
ceving il

10

Puoi infatti usare rangesenza fare riferimento ai suoi valori di ritorno usando for rangecontro il tuo 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


3
Buono a sapersi, ma nella maggior parte dei casi non sarà utile
Sridhar,

D'accordo @Sridhar è piuttosto di nicchia.
Robstarbuck,

10

Di seguito è riportato il codice di esempio su come utilizzare foreach in golang

package main

import (
    "fmt"
)

func main() {

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

    for index,element := range arrayOne{

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

    }   

}

Questo è un esempio corrente https://play.golang.org/p/LXptmH4X_0


ottima spiegazione!
Darlan Dieterich,

A volte è l'esempio più semplice che è il più utile. Grazie! Non ho nulla contro le risposte più esoteriche degli altri commentatori - certamente illustrano le complessità della programmazione Go molto idiomatica, al punto che diventano ... illeggibili e difficili da seguire - ma preferisco la tua risposta: va dritto al centro con l'esempio più semplice possibile (che funziona ed è ovvio perché funziona).
Gwyneth Llewelyn

4

Sì, intervallo :

La forma di intervallo del ciclo for scorre su una sezione o una mappa.

Quando si estende su una sezione, vengono restituiti due valori per ogni iterazione. Il primo è l'indice e il secondo è una copia dell'elemento in quell'indice.

Esempio :

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)
    }
}
  • È possibile saltare l'indice o il valore assegnando a _.
  • Se desideri solo l'indice, elimina interamente il valore.

1

Questo può essere ovvio, ma puoi incorporare l'array in questo modo:

package main

import (
    "fmt"
)

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

uscite:

abc

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.