Code Fix

中級

close of closed channel パニックの原因と直し方

一度closeしたチャネルをもう一度closeしようとすると、実行時にパニックが発生します。複数箇所からcloseを呼びうるコードでは、どこか1箇所だけが責任を持つ設計にする必要があります。

エラーメッセージの読み方

panic: close of closed channel
panic
パニック — 実行時に回復不能な状態になったことを示します。deferとrecoverで捕まえない限り、そのままプロセスが終了します
close of closed channel
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan int)
 5  	close(ch)
 6  	close(ch)
         ^
 7  }
panic: close of closed channel

一度closeしたチャネルをもう一度closeすると、無視されずに実行時パニックになります。

直し方: close(ch)_ = ch にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan string)
 5  	close(ch)
 6  	close(ch) 
          ^
 7  }
panic: close of closed channel

複数箇所からcloseを呼びうるコードでは、どこか1箇所だけが責任を持つように設計する必要があります。

直し方: close(ch)_ = ch にします。

この問題を解いてみる →

パターン3

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan bool)
 5  	close(ch)
 6  	close(ch) 
          ^
 7  }
panic: close of closed channel

送信側と受信側の両方がcloseを呼ぶような設計は、2回目のcloseでパニックする典型的な原因です。

直し方: close(ch)_ = ch にします。

この問題を解いてみる →

パターン4

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan int, 2)
 5  	close(ch)
 6  	close(ch)
         ^
 7  }
panic: close of closed channel

バッファ付きチャネルでも、closeの二重呼び出しに対する挙動は変わりません。

直し方: close(ch)_ = ch にします。

この問題を解いてみる →

パターン5

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan float64)
 5  	close(ch)
 6  	close(ch)
         ^
 7  }
panic: close of closed channel

closeされているかどうかは呼び出し側からは分からないため、二重closeを防ぐ設計上の工夫が必要です。

直し方: close(ch)_ = ch にします。

この問題を解いてみる →

よくある誤解

「closeを複数回呼んでも、2回目以降は何もしない安全な操作のはず」という思い込みは誤りです。2回目のcloseは黙って無視されず、その場でパニックします。

まとめ

close of closed channel パニックの原因と直し方は中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)