地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Go】for selectパターンメモ

チャネルからの受信を待つパターンでの実装。書き込めるチャネルを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でやってるときにチャネルに何もデータがこなければメインゴルーチンで他の処理を行うみたいなことができたりする。