channel の close と range による受信ループ
channel には「もうこれ以上送信しない」ことを伝える仕組みがあります。close です。close された channel に対して range を使うと、すべてのデータを受信し終わるまでループできます。
channel を close する
close 関数で channel を閉じます。
ch := make(chan int)
close(ch)close された channel からは、もう送信できません。送信しようとすると panic になります。
一方、受信は可能です。close 前に送信されたデータがあればそれを受信し、なければゼロ値が返ります。
close されたかどうかを確認する
受信時に 2 つ目の戻り値で、channel が開いているかどうかを確認できます。
v, ok := <-ch
if !ok {
fmt.Println("channel は閉じられています")
}ok が false なら、channel は close されていて、もうデータは来ません。
range で受信ループ
for range を使うと、channel が close されるまで受信し続けることができます。
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 1; i <= 5; i++ {
ch <- i
}
close(ch)
}()
for v := range ch {
fmt.Println(v)
}
}goroutine が 1 から 5 まで送信した後、channel を close しています。for range は close を検知すると自動的にループを終了します。
close を忘れると、range は永遠に待ち続けてデッドロックになるので注意してください。
close するのは送信側
一般的なルールとして、channel を close するのは送信側の責任です。
すべてのデータを送り終えたら close する。
close はしない。range や ok チェックで終了を検知する。
受信側が close すると、まだ送信しようとしている goroutine が panic を起こす可能性があります。
いつ close が必要か
close が必要なのは、受信側が「もう終わり」を知る必要があるときです。たとえば range ループで受信する場合や、複数の goroutine が終了を待っている場合などです。
逆に、受信回数が決まっていて、それだけ受信すれば済むなら close は不要なこともあります。