为了账号安全,请及时绑定邮箱和手机立即绑定

轮询功能的惯用方式,直到 ok != true in go

轮询功能的惯用方式,直到 ok != true in go

Go
Smart猫小萌 2021-06-16 18:29:38
我有一个函数,它在轮询时返回值,但在某些时候将停止返回合理的值,如下所示。有没有比if !ok每次都检查更惯用的方式来轮询它。我正在考虑类似于使用range.package mainimport "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 回答

?
白衣非少年

TA贡献1155条经验 获得超0个赞

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


for v,ok := f(); ok; v,ok = f() {

    fmt.Println(v)

}

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


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


您有一个或多个只有一个返回值的函数需要检查


不幸的是,Go 不会让你做这样的事情


f := iter()

g := iter()

v,ok,v2,ok2 := f(), g(); ok && ok2; v,ok,v2,ok2 := f(), g() {

   // code

}

因此,如果您有一个包含多个函数的案例,除非它们只返回一个值,否则您会被 if 和中断所困扰。


也就是说,(以及反思),在 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)

    }

}

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


查看完整回答
反对 回复 2021-06-21
?
动漫人物

TA贡献1815条经验 获得超10个赞

我看不出你的例子与文件结束之前阅读的常见习语有何不同。例如,


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

你的例子对我来说看起来很惯用。


查看完整回答
反对 回复 2021-06-21
  • 2 回答
  • 0 关注
  • 173 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信