Go:抽象可迭代

时间:2015-07-06 15:57:48

标签: go iterable

假设我想要一个 返回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,我应该考虑别的什么?

3 个答案:

答案 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.Rowsbufio.Scanner中的模式。两者都有一个返回bool的next-equivalent函数,指示是否已成功获取下一个项目。然后有一个单独的方法来访问值和错误。此模式允许您在没有复杂条件的情况下编写非常干净的for循环(并且不使用breakcontinue语句)并在循环外部移动错误处理。

如果你要抽象你的线路输入,你可以创建一个这样的界面:

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

http://play.golang.org/p/LRbGWj9_Xw