As other mates said you can work with channels to implement Generator design pattern which is what you're looking for.
Generator functions
Channels and goroutines provide a natural substrate for implementing a form of
producer/producer pattern using generator functions. In this approach, a goroutine is
wrapped in a function which generates values that are sent via a channel returned by the
function. The consumer goroutine receives these values as they are generated.
Example extracted from Go Design Patterns For Real-World
package main
import (
"fmt"
"strings"
)
func main() {
data := []string{"Sphinx of black quartz, judge my vow",
"The sky is blue and the water too",
"Cozy lummox gives smart squid who asks for job pen",
"Jackdaws love my big sphinx of quartz",
"The quick onyx goblin jumps over the lazy dwarf"}
histogram := make(map[string]int)
words := words(data) // returns handle to data channel
for word := range words { // Reads each word from channel every time
histogram[word]++
}
fmt.Println(histogram)
}
// Generator function that produces data
func words(data []string) <-chan string {
out := make(chan string)
// Go Routine
go func() {
defer close(out) // closes channel upon fn return
for _, line := range data {
words := strings.Split(line, " ")
for _, word := range words {
word = strings.ToLower(word)
out <- word // Send word to channel
}
}
}()
return out
}
https://play.golang.org/p/f0nynFWbEam
In this example, the generator function, declared as func words(data []string) <-
chan string, returns a receive-only channel of string elements. The consumer function, in this instance main(), receives the data emitted by the generator function, which is processed using a for…range loop.
An improved version of this design pattern:
https://play.golang.org/p/uyUfz3ALO6J
Adding methods like Next and Error:
type iterator struct {
valueChan <-chan interface{}
okChan <-chan bool
errChan <-chan error
err error
}
func (i *iterator) next() (interface{}, bool) {
var (
value interface{}
ok bool
)
value, ok, i.err = <-i.valueChan, <-i.okChan, <-i.errChan
return value, ok
}
func (i *iterator) error() error {
return i.err
}
// Generator function that produces data
func NewIterator(data []string) iterator {
out := make(chan interface{})
ok := make(chan bool)
err := make(chan error)
// Go Routine
go func() {
defer close(out) // closes channel upon fn return
for _, line := range data {
words := strings.Split(line, " ")
for _, word := range words {
word = strings.ToLower(word)
out <- word // Send word to channel and waits for its reading
ok <- true
err <- nil // if there was any error, change its value
}
}
out <- ""
ok <- false
err <- nil
}()
return iterator{ out, ok, err, nil }
}