チャネルからの受信を待つパターンでの実装。書き込めるチャネルをselectして実行みたいなのも可能。
package main import ( "fmt" "strconv" "time" ) type Result struct { Error error Response int } func doSomething(done <-chan interface{}, printStr <-chan string) <-chan Result { result := make(chan Result) go func() { defer fmt.Println("タスク終了") defer close(result) for { select { case s := <-printStr: i, err := strconv.Atoi(s) if err != nil { result <- Result{Error: err, Response: 0} } else { result <- Result{Error: err, Response: i} } case <-done: return } } }() return result } func main() { done := make(chan interface{}) printStr := make(chan string) result := doSomething(done, printStr) //1秒後にdoSomethingを終了 go func() { pushData := []string{"1", "bad1"} for _, v := range pushData { printStr <- string(v) } time.Sleep(1 * time.Second) fmt.Println("doSomethingを終了") close(done) }() //doSomething終了に伴いresultがcloseされる。 for res := range result { if res.Error != nil { fmt.Println("error:", res.Error) continue } fmt.Println("Result:", res.Response) } fmt.Println("Finished !!") }
defaultの使い所
selectには該当するチャネルがなければ実行するというようなdefaultを書くことができる。例えばIOバウンドな処理をABでやってるときにチャネルに何もデータがこなければメインゴルーチンで他の処理を行うみたいなことができたりする。