轮询功能的idomatic方法,直到ok!= go中的true

Fer*_*uzz 2 go

我有一个函数在轮询时返回值,但在某些时候将停止返回合理的值,如下所示.

是否有更惯用的方式进行轮询,而不是if !ok每次检查.我正在考虑类似于使用某个频道进行投票range.

package main

import "fmt"

func iter() func() (int, bool) {
    i := 0
        return func() (int, bool) {
        if i < 10 {
            i++
            return i, true
        }
        return i, false
    }
}

func main() {
    f := iter()
    for {
        v, ok := f()
        if !ok {
            break
        }
        fmt.Println(v)
    }
}
Run Code Online (Sandbox Code Playgroud)

Lin*_*ope 6

我认为没有办法避免检查确定,但你可以重组它以避免丑陋的休息:

for v,ok := f(); ok; v,ok = f() {
    fmt.Println(v)
}
Run Code Online (Sandbox Code Playgroud)

应该注意的是,这只适用于以下任何一种情况:

  1. 您有一个具有多个要检查的返回值的函数,OR

  2. 您有一个或多个函数只有一个返回值要检查

不幸的是Go不会让你做的事情

f := iter()
g := iter()
v,ok,v2,ok2 := f(), g(); ok && ok2; v,ok,v2,ok2 := f(), g() {
   // code
}
Run Code Online (Sandbox Code Playgroud)

因此,如果你有一个具有多个函数的情况,你就会遇到ifs和break,除非它们只返回一个值.

也就是说,(并且在反思中),在Go中编写迭代器的更惯用的方法是在一个通道上.考虑等效的程序:

func Iterator(iterCh chan<- int) {
    for i := 0; i < 10; i++ {
       iterCh <- i
    }
    close(iterCh)
}

func main() {
    iter := make(chan int)
    go Iterator(iter)
    for v := range iter {
       fmt.Println(v)
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,只需在完成发送值时关闭通道,而不是返回布尔值.这种方法的缺点是,如果要返回多个值,则必须创建某种类型的结构以通过通道发送.

最后,如果你想在每次运行迭代器时将它包装起来隐藏通道样板:

func Iter() <-chan int {
   iterChan := make(chan int)
   go iter(iterChan)
   return iterChan
}
func iter(iterCh chan<- int) {
    for i := 0; i < 10; i++ {
       iterCh <- i
    }
    close(iterCh)
}

func main() {
    for v := range Iter() {
       fmt.Println(v)
    }
}
Run Code Online (Sandbox Code Playgroud)

这是初始实现的更多代码,但是每次要使用迭代器时都必须手动声明通道.