Go'da bir foreach döngüsü var mı?


Yanıtlar:


851

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

"Aralık" yan tümcesine sahip bir "for" ifadesi, bir dizinin, dilimin, dizenin veya haritanın tüm girdileri veya bir kanalda alınan değerler arasında yinelenir. Her giriş için yineleme değerlerini karşılık gelen yineleme değişkenlerine atar ve ardından bloğu yürütür.

Örnek olarak:

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

Dizinle ilgilenmiyorsanız şunları kullanabilirsiniz _:

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

Alt çizgi, _olduğu boş tanımlayıcı , anonim tutucudur.


7
Bu örnekte, elementbir değer elemanı (kopya) ve - bu elemanın kendisinin değil. Atayabilirsiniz element, ancak bu altta yatan diziyi etkilemez.
nobar

Python ve C yerelleştirme (yani gettext ) için bir işlev olarak alt çizgi kullanmak sık olduğunu biliyorum . Alt çizgi kullanımı Go'da sorun yaratır mı? Go, yerelleştirme için aynı kütüphaneyi bile kullanıyor mu?
Sergiy Kolodyazhnyy

2
@SergiyKolodyazhnyy Py docs "(gettext) işlevi genellikle diğer ad olarak diyor _()yerel ad" adildir Kongre tarafından , bu yerelleştirme lib parçası değil. Alt çizgi _geçerli bir etikettir ve ayrıca _kullanmayacağınız dönüş değerleri için atamak Go (ve Python ve Scala ve diğer dillerde) konvansiyonudur . _Bu örnekteki kapsam , fordöngünün gövdesi ile sınırlıdır . Paket kapsamlı bir işleve sahipseniz _, for döngüsü kapsamı içinde gölgelenir. Yerelleştirme için birkaç paket var, _işlev adı olarak herhangi bir kullanım görmedim .
Davos

149

Go'nun benzer bir foreachsözdizimi vardır. Dizileri / dilimleri, haritaları ve kanalları destekler.

Dizi veya dilim üzerinde yineleme :

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

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

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

Bir harita üzerinde yineleme yapın :

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

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

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

Bir kanal üzerinden yineleme :

for v := range theChan {}

Kanal üzerinden yineleme, kapatılana kadar bir kanaldan alma işlemine eşdeğerdir:

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

10
OP sadece dilim kullanımını istemesine rağmen, bu cevabı tercih ederim, çünkü çoğu zaman diğer kullanımlara da ihtiyaç duyacaktır.
domoarigato

3
chankullanımla ilgili önemli bir ayrım : bir kanal üzerinde dolaşmak, yazar kanalı bir noktada kapatırsa döngüden zarif bir şekilde çıkacaktır. In for {v := <-theChan} eşdeğeri , bu olacak değil kanal kapanırken çıkın. Bunu ikinci okdönüş değeri üzerinden test edebilirsiniz . TUR ÖRNEĞİ
colm.anseo

Aynı şeyi okurken de düşündüm, for { ... }sonsuz bir döngü anlamına gelir.
Levite

13

Aşağıdaki örnek, rangebir fordöngü uygulamak için işlecin bir döngüde nasıl kullanılacağını gösterir foreach.

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

Örnek, işlevlerin hata işlemesini birleştirmek için bir dizi işlev üzerinde yinelenir. Bunun tam bir örneği Google'ın oyun alanındadır .

Not: asılı parantezlerin kodun okunabilirliği için kötü bir fikir olduğunu da gösterir. İpucu: fordurum action()çağrıdan hemen önce sona erer . Açık, değil mi?


3
Bir ekleyin ,ve durumun nerede forsona erdiği daha açık : play.golang.org/p/pcRg6WdxBd - Bu aslında go fmtstile karşı bir karşı argüman bulduğumda , teşekkürler!
tops

@topskip her ikisi de geçerli fmt geçerlidir; sadece en iyi olanı seç :)
Filip Haglund

@FilipHaglund Geçerli olduğu nokta değil. Mesele şu ki, IMO, yukarıdaki koşulda for koşulunun nerede sona erdiği daha açıktır.
topskip

8
Bence bu cevap, hedeflenen soru için makul olmayan bir şekilde karmaşık.
AndreasHassing

@AndreasHassing Yedeklilik getirmeden bunun yerine nasıl yapılır?
ceving

10

Aslında , türünüze karşı rangekullanarak dönüş değerlerine başvurmadan kullanabilirsiniz for range:

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
Bilmek güzel ama bu çoğu durumda kullanışlı olmayacak
Sridhar

@Sridhar hoş bir niş kabul etti.
robstarbuck

9

Aşağıda golang'da foreach kullanımı için örnek kod verilmiştir

package main

import (
    "fmt"
)

func main() {

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

    for index,element := range arrayOne{

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

    }   

}

Bu, çalışan bir örnektir https://play.golang.org/p/LXptmH4X_0


çok iyi bir açıklama!
Darlan Dieterich

4

Evet, Menzil :

For döngüsünün aralık formu bir dilim veya harita üzerinde yinelenir.

Bir dilim üzerinde çalışırken, her yineleme için iki değer döndürülür. Birincisi dizin, ikincisi o dizindeki öğenin bir kopyasıdır.

Misal :

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)
    }
}
  • _ Öğesine atayarak dizini veya değeri atlayabilirsiniz.
  • Yalnızca dizini istiyorsanız,, değerini tamamen bırakın.

1

Bu açık olabilir, ancak diziyi şu şekilde satır içine alabilirsiniz:

package main

import (
    "fmt"
)

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

çıktılar:

abc

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.