มีวง foreach ใน Go หรือไม่?


565

มีforeachโครงสร้างในภาษา Go หรือไม่? ฉันสามารถวนซ้ำชิ้นหรือแถวโดยใช้for?



1
การใช้งานของrangeในforลูปยังกล่าวถึงใน "สลับฉากข้อมูลเกี่ยวกับประเภท" ส่วน (ตรงปลายของมัน) ของไปกวดวิชา
kostix

คำตอบ:


851

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

ประโยค "for" ที่มีคำสั่ง "range" วนซ้ำผ่านรายการทั้งหมดของอาร์เรย์ชิ้นสตริงหรือแผนที่หรือค่าที่ได้รับบนช่องสัญญาณ สำหรับแต่ละรายการจะกำหนดค่าการทำซ้ำให้กับตัวแปรการทำซ้ำที่สอดคล้องกันจากนั้นเรียกใช้งานบล็อก

ตัวอย่างเช่น:

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

หากคุณไม่สนใจเกี่ยวกับดัชนีคุณสามารถใช้_:

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

ขีดเส้นใต้_เป็นตัวระบุที่ว่างเปล่าซึ่งเป็นตัวยึดที่ไม่ระบุตัวตน


7
ในตัวอย่างนี้elementคือค่าขององค์ประกอบ (สำเนา) - มันไม่ใช่องค์ประกอบของตัวเอง แม้ว่าคุณสามารถกำหนดให้กับelementสิ่งนี้จะไม่ส่งผลกระทบต่อลำดับพื้นฐาน
nobar

ฉันรู้ใน Python และ C บ่อยครั้งที่ใช้ขีดล่างเป็นฟังก์ชันสำหรับการโลคัลไลเซชัน (เช่นgettext ) การใช้ขีดเส้นใต้จะทำให้เกิดปัญหาใน Go หรือไม่? Go ใช้แม้แต่ไลบรารี่เดียวกันสำหรับการแปลภาษาหรือไม่?
Sergiy Kolodyazhnyy

2
@SergiyKolodyazhnyy Py docs พูดว่า "(gettext) ฟังก์ชั่นมักจะใช้นามแฝงเหมือน_()ใน namespace ท้องถิ่น" ซึ่งเป็นเพียงการประชุมมันไม่ได้เป็นส่วนหนึ่งของ lib การแปล เครื่องหมายขีดล่าง_เป็นป้ายกำกับที่ถูกต้องและเป็นรูปแบบใน Go (และ Python และ Scala และภาษาอื่น ๆ ) เพื่อกำหนดให้กับ_ค่าส่งคืนที่คุณจะไม่ใช้ ขอบเขตของ_ในตัวอย่างนี้ถูก จำกัด ไว้ที่เนื้อความของforลูป หากคุณมีฟังก์ชั่นกำหนดขอบเขตแพคเกจ_ก็จะเป็นเงาภายในขอบเขตของการวนรอบ มีแพ็คเกจบางส่วนสำหรับการแปลฉันไม่เห็นการใช้งานใด ๆ_เป็นชื่อฟังก์ชัน
Davos

149

Go มีforeachไวยากรณ์เหมือนกัน รองรับอาร์เรย์ / ชิ้นแผนที่และช่อง

ทำซ้ำอาร์เรย์หรือชิ้น :

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

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

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

ย้ำกว่าแผนที่ :

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

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

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

ทำซ้ำผ่านช่อง :

for v := range theChan {}

การวนซ้ำผ่านช่องสัญญาณเทียบเท่ากับการรับสัญญาณจากช่องจนกว่าจะปิด:

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

10
แม้ว่า OP จะขอแค่การใช้งานชิ้นเท่านั้น แต่ฉันชอบคำตอบนี้เพราะส่วนใหญ่จะต้องใช้วิธีอื่นด้วย
domoarigato

3
ความแตกต่างที่สำคัญเกี่ยวกับการchanใช้งาน: การกินช่องสัญญาณจะออกจากลูปถ้าผู้เขียนปิดช่องในบางจุด ในสิ่งที่for {v := <-theChan} เทียบเท่ามันจะไม่ออกเมื่อปิดช่อง คุณสามารถทดสอบสิ่งนี้ได้ด้วยokค่าส่งคืนที่สอง ตัวอย่างทัวร์ของเรา
colm.anseo

คิดเหมือนกันเมื่ออ่านมันfor { ... }หมายถึงการวนซ้ำไม่สิ้นสุด
Levite

13

ตัวอย่างต่อไปนี้แสดงวิธีใช้rangeโอเปอเรเตอร์ในforลูปเพื่อใช้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;
}

ตัวอย่างวนซ้ำฟังก์ชันอาร์เรย์เพื่อรวมการจัดการข้อผิดพลาดสำหรับฟังก์ชัน เป็นตัวอย่างที่สมบูรณ์แบบที่ Google's สนามเด็กเล่น

PS: มันแสดงให้เห็นด้วยว่าวงเล็บปีกกาห้อยเป็นความคิดที่ไม่ดีสำหรับการอ่านรหัส คำแนะนำ: forเงื่อนไขสิ้นสุดก่อนการaction()โทร เห็นได้ชัดใช่มั้ย


3
เพิ่ม a ,และเป็นที่ชัดเจนยิ่งขึ้นเมื่อforเงื่อนไขสิ้นสุดลง: play.golang.org/p/pcRg6WdxBd - อันที่จริงนี่เป็นครั้งแรกที่ฉันได้พบการโต้แย้งโต้แย้งในgo fmtสไตล์ขอบคุณ!
topskip

@topskip ทั้งสองใช้ได้ไป fmt ที่ถูกต้อง; เพียงแค่เลือกหนึ่งที่ดีที่สุด :)
ฆา Haglund

@FilipHaglund มันไม่ได้เป็นจุดถ้ามันถูกต้อง ประเด็นก็คือ IMO นั้นจะชัดเจนขึ้นซึ่งเงื่อนไขสำหรับเงื่อนไขสิ้นสุดลงในกรณีเฉพาะด้านบน
topskip

8
ในความคิดของฉันคำตอบนี้มีความซับซ้อนเกินสมควรสำหรับคำถามที่ตั้งเป้าหมาย
AndreasHassing

@AndreasHassing วิธีการทำแทนโดยไม่แนะนำซ้ำซ้อน?
ceving

10

ในความเป็นจริงคุณสามารถใช้งานได้rangeโดยไม่ต้องอ้างอิงถึงค่าที่ส่งคืนโดยใช้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
เป็นการดีที่จะทราบ แต่นั่นจะไม่เป็นประโยชน์ในกรณีส่วนใหญ่
Sridhar

เห็นด้วย @Sridhar มันเป็นช่องสวย
robstarbuck

9

ต่อไปนี้เป็นตัวอย่างโค้ดสำหรับวิธีใช้ foreach ใน golang

package main

import (
    "fmt"
)

func main() {

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

    for index,element := range arrayOne{

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

    }   

}

นี่เป็นตัวอย่างการรันhttps://play.golang.org/p/LXptmH4X_0


คำอธิบายที่ดีมาก!
Darlan Dieterich

4

ใช่ช่วง :

รูปแบบช่วงของการวนซ้ำวนซ้ำผ่านชิ้นหรือแผนที่

เมื่อมีค่ามากกว่าการแบ่งเป็นสองค่าจะถูกส่งกลับสำหรับการวนซ้ำแต่ละครั้ง แรกคือดัชนีและที่สองคือสำเนาขององค์ประกอบที่ดัชนีนั้น

ตัวอย่าง:

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)
    }
}
  • คุณสามารถข้ามดัชนีหรือค่าโดยกำหนดให้ _
  • หากคุณต้องการเพียงดัชนีให้ปล่อยค่าทั้งหมด

1

สิ่งนี้อาจเห็นได้ชัด แต่คุณสามารถแทรกแถวลำดับลงไปได้

package main

import (
    "fmt"
)

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

เอาท์พุท:

abc

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.