假设我想要一个 返回chan
或 a slice
的方法。例如,如果我想要"关注"我需要chan
。一个文件作为新行,一个切片,如果我只想读取并返回现有行。
在这两种情况下,我只需要遍历此返回值。这是Python中的一个抽象示例(与文件无关,但有点显示了这个想法):
def get_iterable(self):
if self.some_flag:
return (x for x in self.some_iterable)
return [x for x in self.some_iterable]
def do_stuff(self):
items = self.get_iterable()
for item in items:
self.process(item)
现在,我在Go中遇到这个困难。我想我应该寻找类似于#34;可迭代界面的东西"我应该回来,但我没有谷歌一些现成的解决方案(对不起,如果它只是我糟糕的谷歌搜索技能)。
做我想做的最好的方法是什么?或者,也许,整个设计是"坏"对于Go,我应该考虑别的什么?
答案 0 :(得分:3)
或许,整个设计对于Go来说是“糟糕的”,我应该考虑别的什么?
虽然您可以在类型之上构建一些界面,以便您可以像处理它们一样处理它们,我会说这是一个糟糕的选择。更简单的方法是利用多个返回类型并使用chan myType, []myType, error
定义你的func,然后使用3路if-else来检查错误,然后是chan或slice。像往常一样读取通道,像往常一样迭代切片。将在myType
上有效的代码放在辅助方法中,这样就可以从两个控制流中调用它。
我的钱说这不再是代码,它也更直接。我不需要阅读一些抽象来理解我有一个通道和它带来的继承复杂性(陈和切片是不协调的,所以试图模仿它们像噩梦一样的声音),而你只是有程序控制流程中的一个额外步骤。
答案 1 :(得分:2)
我有点迟到了,但如果你真的需要一些“抽象可迭代”,你可以创建一个这样的界面:
type Iterable interface {
Next() (int, error)
}
(灵感来自sql.Rows
。)
然后,您可以像这样使用它:
for n, err := iter.Next(); err != nil; n, err = iter.Next() {
fmt.Println(n)
}
答案 2 :(得分:0)
对于迭代,我通常会遵循sql.Rows和bufio.Scanner中的模式。两者都有一个返回bool的next-equivalent函数,指示是否已成功获取下一个项目。然后有一个单独的方法来访问值和错误。此模式允许您在没有复杂条件的情况下编写非常干净的for
循环(并且不使用break
或continue
语句)并在循环外部移动错误处理。
如果你要抽象你的线路输入,你可以创建一个这样的界面:
type LineScanner interface {
Scan() bool
Text() string
Err() error
}
这会给你和抽象线源阅读器。作为奖励,通过使用这些方法名称,您可以使bufio.Scanner
立即实现您的界面,因此您可以将它与您自己的类型一起使用,例如您的问题中提到的类似尾部的阅读器。
富勒示例:
package main
import (
"bufio"
"fmt"
"strings"
)
type LineScanner interface {
Scan() bool
Text() string
Err() error
}
func main() {
var lr LineScanner
// Use scanner from bufio package
lr = bufio.NewScanner(strings.NewReader("one\ntwo\nthree!\n"))
// Alternatively you can provide your own implementation of LineScanner,
// for example tail-like, blocking on Scan() until next line appears.
// Very clean for loop, isn't it?
for lr.Scan() {
// Handle next line
fmt.Println(lr.Text())
}
// Check if no error while reading
if lr.Err() != nil {
fmt.Println("Error:", lr.Err())
}
}