轮询函数的惯用方法,直到ok!= go中的true

时间:2013-07-25 19:42:02

标签: 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)
    }
}

2 个答案:

答案 0 :(得分:6)

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

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

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

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

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

  3. 不幸的是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)
        }
    }
    

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

答案 1 :(得分: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

你的例子看起来不合时宜。