channel【Go】
channelを使って、goroutineと関数の間で、データをやり取りすることができます。
次の例では、スライスの中身を足し合わせた結果を、channelを使って返却します。
func useChannel(s []int, c chan int) { var sum int for _, v := range s { sum += v } c <- sum // sumをchannelに入れて返却 } func main() { s := []int{2, 3, 7, 8} c := make(chan int) // channelはint型を指定(サイズを指定しないunbuffered channel。デフォルトでサイズは0) go useChannelS(s, c) x := <-c // 返ってきたchannelを受け取る fmt.Println(x) // 20 }
goroutineの処理の後に記述した、channelの中身を変数に格納する処理
x := <-c
は、後続の処理をブロッキングするため、sync.WaitGroup.Wait()などは必要ありません。
上記例では、最終的な合計結果(sum)をchannelに渡していますが、
close(channel)と,channelからの送信の際にfor文を用いると、
途中経過を出力することができます。
func useChannel(s []int, c chan int) { var sum int for _, v := range s { sum += v c <- sum // 毎回sumを受信 } close(c) // forループから抜けたらcloseすることで、cをrangeで回す際の終点を知らせる } func main() { s := []int{2, 3, 8, 9, 12} c := make(chan int, len(s)) // 第2引数を指定して、あらかじめ容量を確保 go useChannel(s, c) for i := range c { fmt.Println(i) // 受信の都度出力 } }
もちろん、channelの型はint以外にも対応します。
stringの例です。
func useChannelS(s string, c chan string) { c <- s + "を受け取りましたので返します。" } func main() { c2 := make(chan string) go useChannelS("A", c2) xx := <-c2 fmt.Println(xx) // Aを受け取りましたので返します。 }
channelをinterface型にしてswitch typeを使えば、任意の型を指定することができます。
func interfaceChannel(i interface{}, c chan interface{}) { var rv interface{} switch ii := i.(type) { case string: rv = ii + "ですね" case int: rv = ii + 100 default: rv = "undefined" } c <- rv } func main() { // crypto/randパッケージを使用した乱数生成 seed, _ := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) rand.Seed(seed.Int64()) rn := rand.Int63() % 2 var i interface{} if rn == 0 { i = 13 } else { i = "あかさたな" } c3 := make(chan interface{}) go interfaceChannel(i, c3) xxx := <-c3 fmt.Println(xxx) }
channelに関する、実に様々なパターンが記述されています。
hori-ryota.com