ruk·si

Go
Iterator Patterns

Updated at 2013-11-18 06:54

Iteration pattern allows a programmer to traverse a container without knowing anything about the implementation. Closely resembles a basic for-loop.

package main

import "fmt"

func main() {
    letters := []string{"a", "b", "c", "d"}
    for index, item := range letters {
        fmt.Printf("[%d]: %s\n", index, item)
    }
}

Callback iterator pattern is the fastest.

package main

import "fmt"

// Iterator.
func IntCallbackIterator(integers []int, callback func(int)) {
    for _, value := range integers {
        callback(value)
    }
}

// Usage
func main() {
    var sum int = 0
    var numbers = []int{1, 2, 3, 4}
    IntCallbackIterator(numbers, func(value int) {
        sum += value
    })
    fmt.Println(sum)
}

Closure iterator pattern is pretty close to callback iterator in performance.

package main

import "fmt"

// Container returns this.
type IntIterator interface {
    Next() (int, bool)
}

// Iterator.
func IntClosureIterator(integers []int) (func() (int, bool), bool) {
    var index = 0
    var length = len(integers)
    return func() (int, bool) {
        var prevIndex = index
        index++
        return integers[prevIndex], (index < length)
    }, (index < length)
}

// Usage
func main() {
    var sum = 0
    var numbers = []int{1, 2, 3, 4}
    var currentValue = 0
    for it, hasNext := IntClosureIterator(numbers); hasNext; {
        currentValue, hasNext = it()
        sum += currentValue
    }
    fmt.Println(sum)
}

Channel iterator pattern is the most natural to use in Go.

package main

import "fmt"

func IntChannelIterator(integers []int) <-chan int {
    ch := make(chan int, len(integers))
    go func() {
        for _, value := range integers {
            ch <- value
        }
        close(ch)
    }()
    return ch
}

func main() {
    var sum = 0
    var numbers = []int{1, 2, 3, 4}
    for value := range IntChannelIterator(numbers) {
        sum += value
    }
    fmt.Println(sum)
}