Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go: abstract iterable

Tags:

iterable

go

Suppose I want to have a method that should either return a chan or a slice. For example, I need a chan if I want to "follow" a file as new lines come, and a slice if I just want to read and return existing lines.

In both cases I will only have to iterate through this return value. Here is an abstract example in Python (which has nothing to do with files but sort of shows the idea):

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)

Now, I have a difficulty doing this in Go. I suppose I should look for something like an "iterable interface" which I should return, but I failed to google up some ready-to-use solutions (sorry if it's just my poor googling skills).

What is the best way to do what I want? Or, maybe, the whole design is "bad" for Go and I should consider something else?

like image 648
oopcode Avatar asked Feb 12 '26 14:02

oopcode


2 Answers

Or, maybe, the whole design is "bad" for Go and I should consider something else?

While you could build some interface on top of the types so that you can deal with them as if they were the same I would say it's a poor choice. The far simpler one is to take advantage of multiple return types and define your func with chan myType, []myType, error for it's return then just use 3 way if-else to check for error, followed by chan or slice. Read of the channel like you normally would, iterate the slice like you normally would. Put the code that does work on myType in a helper method so you can call it from both control flows.

My money says this is no more code and it's also far more straight forward. I don't have to read through some abstraction to understand that I have a channel and the inherit complications that come along with it (chan and a slice are incongruous so trying to model them the same sounds like a nightmare), instead you just have an extra step in the programs control flow.

like image 160
evanmcdonnal Avatar answered Feb 14 '26 03:02

evanmcdonnal


I'm kinda late to the party, but if you really need some "abstract iterable", you could create an interface like this:

type Iterable interface {
    Next() (int, error)
}

(Inspired by sql.Rows.)

Then, you could use it like this:

for n, err := iter.Next(); err != nil; n, err = iter.Next() {
    fmt.Println(n)
}
like image 24
Ainar-G Avatar answered Feb 14 '26 03:02

Ainar-G



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!