Channels exhibit the following properties:
package main
func main() {
var ch chan bool
ch <- true // deadlocks because ch is nil
}
Uninitialized value of a channel is nil
so the above program blocks forever.
There's no valid use case for that so it's always a bug. Don't do it.
package main
import "fmt"
func main() {
var ch chan bool
fmt.Printf("Value received from ch is: %v\\n", <-ch) // deadlock because c is nil
}
Similarly, receive from nil
channel blocks forever and it's always a bug. Don't do it.
package main
import (
"fmt"
"time"
)
func main() {
var ch = make(chan int, 100)
go func() {
ch <- 1
time.Sleep(time.Second)
close(ch)
ch <- 1
}()
for i := range ch {
fmt.Printf("i: %d\\n", i)
}
}
Output:
i: 1
panic: send on closed channel
goroutine 5 [running]:
main.main.func1(0x452000, 0xc99)
/tmp/sandbox307976305/main.go:14 +0xa0
created by main.main
/tmp/sandbox307976305/main.go:10 +0x60
You should architecture your programs so that one sender controls the lifetime of a channel.
This rule emphasizes that: if there's only one channel sender then there's no problem making sure that you never write to a closed channel.
If you have multiple senders then it becomes hard: if one sender closes a channel, how other senders are supposed to not crash?
Instead of trying to find solution to the above problem, re-architect your code so that there's only one sender that controls the lifetime of a channel.