Apakah ada foreach loop di Go?

Jawaban:

851

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

Pernyataan "untuk" dengan klausa "rentang" beriterasi melalui semua entri array, irisan, string atau peta, atau nilai yang diterima pada saluran. Untuk setiap entri itu memberikan nilai iterasi ke variabel iterasi yang sesuai dan kemudian menjalankan blok.

Sebagai contoh:

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

Jika Anda tidak peduli dengan indeks, Anda dapat menggunakan _:

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

Garis bawah,, _adalah pengidentifikasi kosong , tempat penampung anonim.

davetron5000
sumber
7
Dalam contoh ini, elementadalah nilai elemen (salinan) - itu bukan elemen itu sendiri. Meskipun Anda dapat menetapkan element, ini tidak akan mempengaruhi urutan yang mendasarinya.
Nobar
Saya tahu dengan Python dan C sering menggunakan garis bawah sebagai fungsi untuk pelokalan (yaitu gettext ). Apakah penggunaan garis bawah akan menyebabkan masalah di Go? Apakah Go bahkan menggunakan perpustakaan yang sama untuk pelokalan?
Sergiy Kolodyazhnyy
3
@SergiyKolodyazhnyy Py docs mengatakan "fungsi (gettext) biasanya alias seperti _()di namespace lokal" yang hanya dengan konvensi , itu bukan bagian dari lib lokalisasi. Garis bawah _adalah label yang valid, dan itu juga konvensi di Go (dan Python dan Scala dan langs lainnya) untuk menetapkan _nilai pengembalian yang tidak akan Anda gunakan. Lingkup _dalam contoh ini terbatas pada badan forloop. Jika Anda memiliki fungsi paket- _lingkup maka akan dibayangi di dalam lingkup for loop. Ada beberapa paket untuk pelokalan, saya belum melihat penggunaan _sebagai nama fungsi.
Davos
150

Go memiliki foreachsintaks seperti. Ini mendukung array / irisan, peta dan saluran.

Iterate over array atau slice :

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

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

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

Iterate di atas peta :

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

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

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

Iterasi melalui saluran :

for v := range theChan {}

Iterasi melalui saluran sama dengan menerima dari saluran sampai ditutup:

for {
    v, ok := <-theChan
    if !ok {
        break
    }
}
Moshe Revah
sumber
11
Meskipun OP hanya meminta penggunaan slice, saya lebih suka jawaban ini, karena sebagian besar akhirnya akan membutuhkan penggunaan lain juga.
domoarigato
3
perbedaan penting tentang chanpenggunaan: rentang saluran akan dengan anggun keluar dari loop jika penulis menutup saluran di beberapa titik. Dalam for {v := <-theChan} setara , itu tidak akan keluar pada saluran tutup. Anda dapat menguji ini melalui nilai okbalik kedua . CONTOH TOUR
colm.anseo
Pikiran yang sama ketika membacanya, for { ... }singkatan dari infinite loop.
Levite
13

Contoh berikut menunjukkan cara menggunakan rangeoperator dalam satu forloop untuk mengimplementasikan 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;
}

Contoh ini mengulangi array fungsi untuk menyatukan penanganan kesalahan untuk fungsi. Contoh lengkap ada di taman bermain Google .

PS: itu menunjukkan juga bahwa kawat gigi gantung adalah ide yang buruk untuk keterbacaan kode. Petunjuk: forkondisi berakhir tepat sebelum action()panggilan. Jelas, bukan?

ceving
sumber
3
Tambahkan a ,dan lebih jelas di mana forkondisinya berakhir: play.golang.org/p/pcRg6WdxBd - Ini sebenarnya pertama kalinya saya menemukan argumen balasan untuk go fmtstyle, terima kasih!
topskip
@ topskip keduanya berjalan fmt valid; pilih saja yang terbaik :)
Filip Haglund
@FilipHaglund Bukan itu intinya jika valid. Intinya adalah bahwa IMO lebih jelas di mana kondisi untuk berakhir pada kasus khusus di atas.
topskip
9
Menurut pendapat saya, jawaban ini tidak masuk akal kompleks untuk pertanyaan yang ditargetkan.
AndreasHassing
@AndreasHassing Bagaimana cara melakukannya tanpa memperkenalkan redundansi?
ceving
10

Anda sebenarnya bisa menggunakan rangetanpa mereferensikan nilai pengembaliannya dengan menggunakan for rangeterhadap tipe Anda:

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
sumber
3
Baik untuk diketahui tetapi itu tidak akan berguna dalam banyak kasus
Sridhar
Setuju @ridhar itu ceruk yang cukup.
robstarbuck
10

Berikut ini adalah contoh kode untuk cara menggunakan foreach di golang

package main

import (
    "fmt"
)

func main() {

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

    for index,element := range arrayOne{

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

    }   

}

Ini adalah contoh yang sedang berjalan https://play.golang.org/p/LXptmH4X_0

Nisal Edu
sumber
penjelasan yang sangat bagus!
Darlan Dieterich
Terkadang itu contoh paling sederhana yang paling berguna. Terima kasih! Saya tidak menentang jawaban yang paling esoteris dari komentator lain - mereka jelas menggambarkan seluk-beluk pemrograman Go yang sangat idiomatis, hingga mereka menjadi ... tidak dapat dibaca dan sulit diikuti - tetapi saya lebih suka jawaban Anda: langsung saja ke inti dengan contoh paling sederhana yang mungkin (yang bekerja dan jelas mengapa itu berhasil).
Gwyneth Llewelyn
4

Ya, Kisaran :

Bentuk rentang for loop berulang di atas slice atau peta.

Ketika mulai dari satu irisan, dua nilai dikembalikan untuk setiap iterasi. Yang pertama adalah indeks, dan yang kedua adalah salinan elemen pada indeks itu.

Contoh:

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)
    }
}
  • Anda dapat melewati indeks atau nilai dengan menetapkan _.
  • Jika Anda hanya menginginkan indeks, jatuhkan nilai, seluruhnya.
Amitesh
sumber
1

Ini mungkin terlihat jelas, tetapi Anda dapat menyejajarkan array seperti ini:

package main

import (
    "fmt"
)

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

output:

abc

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

jpihl
sumber