他の仲間が言ったように、あなたはあなたが探しているものであるジェネレータデザインパターンを実装するためにチャンネルと協力することができます。
ジェネレーター機能
チャネルとゴルーチンは、ジェネレーター機能を使用してプロデューサー/プロデューサーパターンの形式を実装するための自然な基盤を提供します。このアプローチでは、ゴルーチンは、関数によって返されるチャネルを介して送信される値を生成する関数にラップされます。コンシューマーゴルーチンは、生成時にこれらの値を受け取ります。
実世界のGoデザインパターンから抽出された例
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
この例では、func words(data [] string)<-chan stringとして宣言されたジェネレーター関数は、文字列要素の受信専用チャネルを返します。コンシューマー関数(この例ではmain())は、ジェネレーター関数によって発行されたデータを受け取ります。このデータは、for…rangeループを使用して処理されます。
このデザインパターンの改良版:
https://play.golang.org/p/uyUfz3ALO6J
Nextや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 }
}