Go 语言中有 foreach
构造吗?我可以使用 for
遍历切片或数组吗?
for
循环中 range
的用法。
来自 For statements with range clause:
带有“range”子句的“for”语句遍历数组、切片、字符串或映射的所有条目,或通道上接收的值。对于每个条目,它将迭代值分配给相应的迭代变量,然后执行该块。
举个例子:
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
}
下划线 _
是 blank identifier,一个匿名占位符。
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
}
}
chan
用法的重要区别:如果作者在某个时候关闭通道,则在通道上进行范围将优雅地退出循环。在 for {v := <-theChan}
equivalent 中,它不会在通道关闭时退出。您可以通过第二个 ok
返回值对此进行测试。 TOUR EXAMPLE
for { ... }
代表无限循环。
以下是如何在 Go 中使用 foreach 的示例代码:
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
以下示例说明如何在 for
循环中使用 range
运算符来实现 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 的 playground 提供了一个完整的示例。
PS:它还表明挂大括号对代码的可读性是一个坏主意。提示:for
条件在 action()
调用之前结束。很明显,不是吗?
实际上,您可以通过对您的类型使用 for range
来使用 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
是的,范围:
for 循环的范围形式迭代切片或映射。
在切片上进行测距时,每次迭代都会返回两个值。第一个是索引,第二个是该索引处元素的副本。
例子:
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)
}
}
您可以通过分配给_来跳过索引或值。
如果您只想要索引,请完全删除 , 值。
这可能很明显,但您可以像这样内联数组:
package main
import (
"fmt"
)
func main() {
for _, element := range [3]string{"a", "b", "c"} {
fmt.Print(element)
}
}
输出:
abc
https://play.golang.org/p/gkKgF3y5nmt
我刚刚实现了这个库:https://github.com/jose78/go-collection。
这是如何使用 Foreach 循环的示例:
package main
import (
"fmt"
col "github.com/jose78/go-collection/collections"
)
type user struct {
name string
age int
id int
}
func main() {
newList := col.ListType{user{"Alvaro", 6, 1}, user{"Sofia", 3, 2}}
newList = append(newList, user{"Mon", 0, 3})
newList.Foreach(simpleLoop)
if err := newList.Foreach(simpleLoopWithError); err != nil{
fmt.Printf("This error >>> %v <<< was produced", err )
}
}
var simpleLoop col.FnForeachList = func(mapper interface{}, index int) {
fmt.Printf("%d.- item:%v\n", index, mapper)
}
var simpleLoopWithError col.FnForeachList = func(mapper interface{}, index int) {
if index > 1{
panic(fmt.Sprintf("Error produced with index == %d\n", index))
}
fmt.Printf("%d.- item:%v\n", index, mapper)
}
此执行的结果应该是:
0.- item:{Alvaro 6 1}
1.- item:{Sofia 3 2}
2.- item:{Mon 0 3}
0.- item:{Alvaro 6 1}
1.- item:{Sofia 3 2}
Recovered in f Error produced with index == 2
ERROR: Error produced with index == 2
This error >>> Error produced with index == 2
<<< was produced
element
是元素的 值(副本)——它不是元素本身。尽管您可以分配给element
,但这不会影响基础序列。_()
”,这只是按照惯例,它不是本地化库的一部分。下划线_
是一个有效的标签,它也是 Go(以及 Python 和 Scala 和其他语言)中的约定,将您不会使用的返回值分配给_
。此示例中_
的范围仅限于for
循环的主体。如果您有一个包范围的函数_
,那么它将在 for 循环的范围内被隐藏。有一些本地化包,我没有看到任何使用_
作为函数名。for...range
的更多使用示例,请参阅下面的 Moshe Revah's answer。包括切片、贴图和通道。