In Go is it possible to iterate over a custom type?

Related searches

I have a custom type which internally has a slice of data.

Is it possible, by implementing some functions or an interface that the range operator needs, to iterate (using range) over my custom type?

The short answer is no.

The long answer is still no, but it's possible to hack it in a way that it sort of works. But to be clear, this is most certainly a hack.

There are a few ways you can do it, but the common theme between them is that you want to somehow transform your data into a type that Go is capable of ranging over.

Approach 1: Slices

Since you mentioned that you have a slice internally, this may be easiest for your use case. The idea is simple: your type should have an Iterate() method (or similar) whose return value is a slice of the appropriate type. When called, a new slice is created containing all of the elements of the data structure in whatever order you'd like them to be iterated over. So, for example:

func (m *MyType) Iterate() []MyElementType { ... }

mm := NewMyType()
for i, v := range mm.Iterate() {
    ...
}

There are a few concerns here. First, allocation - unless you want to expose references to internal data (which, in general, you probably don't), you have to make a new slice and copy all of the elements over. From a big-O standpoint, this isn't that bad (you're doing a linear amount of work iterating over everything anyway), but for practical purposes, it may matter.

Additionally, this doesn't handle iterating over mutating data. This is probably not an issue most of the time, but if you really want to support concurrent updates and certain types of iteration semantics, you might care.

Approach 2: Channels

Channels are also something that can be ranged over in Go. The idea is to have your Iterate() method spawn a goroutine that will iterate over the elements in your data structure, and write them to a channel. Then, when the iteration is done, the channel can be closed, which will cause the loop to finish. For example:

func (m *MyType) Iterate() <-chan MyElementType {
    c := make(chan MyElementType)
    go func() {
        for _, v := range m.elements {
            c <- v
        }
        close(c)
    }()
    return c
}

mm := NewMyType()
for v := range mm.Iterate() {
    ...
}

There are two advantages of this method over the slice method: first, you don't have to allocate a linear amount of memory (although you may want to make your channel have a bit of a buffer for performance reasons), and second, you can have your iterator play nicely with concurrent updates if you're into that sort of thing.

The big downside of this approach is that, if you're not careful, you can leak goroutines. The only way around this is to make your channel have a buffer deep enough to hold all of the elements in your data structure so that the goroutine can fill it and then return even if no elements are read from the channel (and the channel can then later be garbage collected). The problem here is that, a) you're now back to linear allocation and, b) you have to know up-front how many elements you're going to write, which sort of puts a stop to the whole concurrent-updates thing.

The moral of the story is that channels are cute for iterating, but you probably don't want to actually use them.

Approach 3: Internal Iterators

Credit to hobbs for getting to this before me, but I'll cover it here for completeness (and because I want to say a bit more about it).

The idea here is to create an iterator object of sorts (or to just have your object only support one iterator at a time, and iterate on it directly), just like you would in languages that support this more directly. What you do, then, is call a Next() method which, a) advances the iterator to the next element and, b) returns a boolean indicating whether or not there's anything left. Then you need a separate Get() method to actually get the value of the current element. The usage of this doesn't actually use the range keyword, but it looks pretty natural nonetheless:

mm := MyNewType()
for mm.Next() {
    v := mm.Get()
    ...
}

There are a few advantages of this technique over the previous two. First, it doesn't involve allocating memory up-front. Second, it supports errors very naturally. While it's not really an iterator, this is exactly what bufio.Scanner does. Basically the idea is to have an Error() method which you call after iteration is complete to see whether iteration terminated because it was done, or because an error was encountered midway through. For purely in-memory data structures this may not matter, but for ones that involve IO (e.g., walking a filesystem tree, iterating over database query results, etc), it's really nice. So, to complete the code snippet above:

mm := MyNewType()
for mm.Next() {
    v := mm.Get()
    ...
}
if err := mm.Error(); err != nil {
    ...
}
Conclusion

Go doesn't support ranging over arbitrary data structures - or custom iterators - but you can hack it. If you have to do this in production code, the third approach is 100% the way to go, as it is both the cleanest and the least of a hack (after all, the standard library includes this pattern).

How do I iterate over an array of a custom type in Go?, I need to take all of the entries with a Status of active and call another function to check the name against an API. In Go you iterate with a for� Go Custom Type Declarations Tutorial With Example is today’s topic. Go is not Object Oriented Programming language like Java, PHP, or Python. It has a unique design pattern. In this tutorial, we will see an approach in which we will define our custom types in Go. Go Custom Type Declarations Tutorial. We can define our own types in Go.

No, not using range. range accepts arrays, slices, strings, maps, and channels, and that's it.

The usual sort of idiom for iterable things (for example a bufio.Scanner) seems to be

iter := NewIterator(...)
for iter.More() {
    item := iter.Item()
    // do something with item
}

but there's no universal interface (wouldn't be very useful given the type system anyway) and different types that implement the pattern generally have different names for their More andItem methods (for example Scan and Text for a bufio.Scanner)

3 ways to iterate in Go, 3 different way to implement an iterator in Go: callbacks, channels, struct with Next() possible iterator so that we can focus on the implementation of the iterator API The name depends on the kind of value we retrieve * optional Err() function� TL;DR It is possible to change type signatures of go structs during runtime and create entirely new types in runtime. This story tells you how. I want to write this starting with a disclaimer: The

joshlf gave an excellent answer, but I'd like to add a couple of things:

Using channels

A typical problem with channel iterators is that you have to range through the entire data structure or the goroutine feeding the channel will be left hanging forever. But this can be quite easily circumvented, here's one way:

func (s intSlice) chanIter() chan int {
    c := make(chan int)
    go func() {
        for _, i := range s {
            select {
            case c <- i:
            case <-c:
                close(c)
                return
            }
        }
        close(c)
    }()
    return c
}

In this case writing back to the iterator channel interrupts the iteration early:

s := intSlice{1, 2, 3, 4, 5, 11, 22, 33, 44, 55}
c := s.chanIter()
for i := range c {
    fmt.Println(i)
    if i > 30 {
        // Send to c to interrupt
        c <- 0
    }
}

Here it is very important that you don't simply break out of the for loop. You can break, but you must must write to the channel first to ensure the goroutine will exit.

Using closures

A method of iteration I often tend to favour is to use an iterator closure. In this case the iterator is a function value, which, when called repeatedly, returns the next element and indicates whether the iteration can continue:

func (s intSlice) cloIter() func() (int, bool) {
    i := -1
    return func() (int, bool) {
        i++
        if i == len(s) {
            return 0, false
        }
        return s[i], true
    }
}

Use it like this:

iter := s.cloIter()
for i, ok := iter(); ok; i, ok = iter() {
    fmt.Println(i)
}

In this case it's perfectly ok to break out of the loop early, iter will eventually be garbage collected.

Playground

Here's the link to the implementations above: http://play.golang.org/p/JC2EpBDQKA

How to best implement an iterator � YourBasic Go, Go has a built-in range loop for iterating over slices, arrays, strings, maps and To iterate over other types of data, an iterator function with callbacks is a clean� Iteration is a frequent need, be it iterating over lines of a file, results or of SELECT SQL query or files in a directory. There are 3 common iteration patterns in Go programs: * callbacks * an iterator object with Next() method * channels

There is another option that wasn't mentioned.

You can define a Iter(fn func(int)) function which accepts some function that will be called for each item in your custom type.

type MyType struct {
    data []int
}

func (m *MyType) Iter(fn func(int)) {
    for _, item := range m.data {
        fn(item)
    }
}

And it can be used like this:

d := MyType{
    data: []int{1,2,3,4,5},
}

f := func(i int) {
    fmt.Println(i)
}
d.Iter(f)

Playground Link to working implementation: https://play.golang.org/p/S3CTQmGXj79

Iterators in Go, A Survey of Iterator (or Generator) Patterns in golang appropriate interface, but this is also the most common type of iterator we need). In all the examples, I'll use iterating over a []int to make the code as simple as possible. The Integer class wraps a value of the primitive type int in an object. An object of type Integer contains a single field whose type is int. More about Integer Object: here Custom ArrayList: A custom arraylist has attributes based on user requirements and can have more than one type of data. This data is provided by a custom inner class which

Because Object.values(meals) returns the object property values in an array, the whole task reduces to a compact for..of loop. mealName is assigned directly in the loop, so there is no need for the additional line like it was in the previous example. Object.values() does one thing, but does it well. This is a true path to clean code. 3.

Second type of PL/SQL Loop: While Loop. In the WHILE loop the condition is checked at the beginning. If false, the loop terminates without a single execution of the statement. If true, the statements within the loop are executed. The loop will repeat until, the condition becomes false.

I have a function that takes in a table name, and I want to loop through the 2 fields in the table, and create a string that has a comma between the 2 fields for a line and a new line for each row. Each of the values would go through some calculations before being added to the string. I need to know

Comments
  • #2 is a lot like generators elsewhere. But yeah, not quite so easy to use. To avoid the leak without a buffered channel takes something like two channels, a select, a defer close, and a bit of care.
  • That, and a client willing to explicitly signal that they're done ranging.
  • An outstanding answer joshif, thanks. I'll go with approach 3.