Go言語のchannelクローズ(close関数)の役割と注意点を解説!初心者向け完全ガイド
生徒
「先生、Go言語でchannelを使った後にclose関数って何のためにあるんですか?」
先生
「channelを閉じることで、送信が完了したことを受信側に伝えるために使います。閉じたchannelに送信はできませんが、受信は残っているデータを受け取ることができます。」
生徒
「なるほど。でも閉じないとどうなるんですか?」
先生
「閉じないと、受信側はデータがもう来ないことがわからず、無限に待ち続けてしまうことがあります。特にループで受信する場合は注意が必要です。」
1. channelのclose関数とは?
Go言語(Golang)のclose関数は、channelを閉じるための関数です。閉じることで、送信がこれ以上行われないことを明示的に示せます。
channelを閉じると受信側は残りのデータを受け取った後、追加のデータが来ないことを確認できます。
閉じたchannelから値を受信すると、ゼロ値とともに第二戻り値のbooleanで「もうデータがない」ことを知ることができます。
2. channelクローズの基本例
簡単な例で、channelを送信してから閉じる方法を見てみましょう。
package main
import "fmt"
func main() {
ch := make(chan int, 3)
// データを送信
ch <- 1
ch <- 2
ch <- 3
// channelを閉じる
close(ch)
// 受信
for v := range ch {
fmt.Println(v)
}
}
この例では、バッファ付きchannelに3つの値を送信したあとにclose(ch)で閉じています。
受信側ではfor v := range chで、channelが閉じられるまでループして値を順番に取り出せます。
実行結果は次の通りです。
1
2
3
3. close関数を使うときの注意点
channelのcloseにはいくつか注意点があります。
- 送信側が複数ある場合、同じchannelを複数のゴルーチンが閉じないようにすること
- 閉じたchannelに送信するとpanicが発生する
- 受信側は閉じたchannelからも値を受け取れるが、ゼロ値が返ることを理解する
例えば、閉じたchannelに送信すると次のようにエラーになります。
package main
func main() {
ch := make(chan int)
close(ch)
ch <- 1 // panic: send on closed channel
}
4. 受信側でcloseを確認する方法
受信側では、channelが閉じているかを第二戻り値で確認できます。これにより、ループを安全に抜けることができます。
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 10
ch <- 20
close(ch)
for {
v, ok := <-ch
if !ok {
fmt.Println("channelは閉じられました")
break
}
fmt.Println(v)
}
}
実行結果:
10
20
channelは閉じられました
このように、okで閉じたかどうかを判定すると、panicを防ぎ安全に処理できます。
5. close関数を活用したパターン
複数のゴルーチンからのデータ送信後にchannelを閉じて、受信側でまとめて処理するパターンがよく使われます。
例えばワーカー処理や、非同期で複数データを集める場合です。
こうした使い方をすることで、受信側は「もう送信はない」とわかり、forループで安全に終了できます。
6. まとめ的な補足ポイント
- channelはデータのやり取り用の通信路で、closeで送信終了を明示できる
- 受信側はrangeや第二戻り値のbooleanで安全に受信完了を確認可能
- 送信側が複数ある場合は閉じるタイミングに注意し、閉じたchannelには送信しない
- close関数はゴルーチン間の同期や終了判定に便利な手段