我有一个函数在轮询时返回值,但在某些时候会停止返回合理的值,如下所示。
是否有更习惯的方式进行轮询,而不是每次都检查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)
}
}
答案 0 :(得分:6)
我认为没有办法避免检查确定,但你可以重组它以避免丑陋的休息:
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
}
因此,如果您有一个具有多个功能的案例,那么除非他们只返回一个值,否则您会遇到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
你的例子看起来不合时宜。