2

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

有没有比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)
    }
}
4

2 回答 2

6

我认为没有办法避免检查确定,但您可以对其进行重组以避免丑陋的中断:

for v,ok := f(); ok; v,ok = f() {
    fmt.Println(v)
}

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

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

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

不幸的是,Go 不会让你做类似的事情

f := iter()
g := iter()
v,ok,v2,ok2 := f(), g(); ok && ok2; v,ok,v2,ok2 := f(), g() {
   // code
}

因此,如果您有一个包含多个函数的案例,除非它们只返回一个值,否则您会被 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)
    }
}

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

最后,如果您想在每次运行迭代器时将其包装一下以隐藏通道样板:

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

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

于 2013-07-25T19:49:14.587 回答
1

我看不出您的示例与直到文件末尾阅读的常见习语有何不同。例如,

package main

import (
    "bytes"
    "fmt"
    "io"
    "strings"
)

func main() {
    buf := bytes.NewBufferString("line1\nline2")
    for {
        line, err := buf.ReadString('\n')
        if err != nil {
            if err != io.EOF {
                fmt.Println(err)
                return
            }
            if len(line) == 0 {
                break
            }
        }
        line = strings.TrimSuffix(line, "\n")
        fmt.Println(line)
    }
}

输出:

line1
line2

你的例子对我来说很地道。

于 2013-07-25T20:47:21.247 回答