channels
(Windsurf GPT 4.1)
Send/Receive Scenarios
Here’s a comprehensive walkthrough of all the key send/receive scenarios with Go channels, focusing on blocking behavior and what is returned in each case:
1. SENDING TO A CHANNEL
a. Unbuffered Channel (e.g., ch := make(chan int)
)
ch := make(chan int)
)Send blocks until another goroutine is ready to receive.
If no receiver: The sender blocks (waits).
If receiver is waiting: Send proceeds immediately; value is transferred.
b. Buffered Channel (e.g., ch := make(chan int, 2)
)
ch := make(chan int, 2)
)Send blocks only if the buffer is full.
If buffer is not full: Send proceeds, value is queued.
If buffer is full: Send blocks until space is available (i.e., a value is received).
c. Sending to a Closed Channel
Always panics at runtime:
panic: send on closed channel
2. RECEIVING FROM A CHANNEL
a. Unbuffered Channel
Receive blocks until another goroutine sends a value.
If no sender: Receiver blocks (waits).
If sender is waiting: Receive proceeds immediately; value is transferred.
b. Buffered Channel
Receive blocks only if the buffer is empty.
If buffer has values: Receive proceeds, value is dequeued.
If buffer is empty: Receive blocks until a value is sent.
c. Receiving from a Closed Channel
If buffer has values: Receive proceeds as normal until buffer is empty.
If buffer is empty: Receive returns the zero value of the channel’s type, and the second "ok" value is false (see below).
3. SELECT STATEMENT
If multiple channels are ready: One is chosen at random.
If none are ready: select blocks unless there is a default case.
4. WHAT IS RETURNED?
a. Regular Receive
gov := <-ch
Blocks as above.
Returns value sent (or zero value if channel is closed and empty).
b. Receive with "ok" idiom
gov, ok := <-ch
If a value is received, ok is true.
If channel is closed and empty, v is zero value, ok is false.
5. SUMMARY TABLE
Send to unbuffered, no receiver
Blocks
N/A
Send to unbuffered, receiver
Does not block
Value transferred
Send to buffered, not full
Does not block
Value added to buffer
Send to buffered, full
Blocks
N/A
Send to closed channel
Panics
panic: send on closed channel
Receive from unbuffered, no send
Blocks
N/A
Receive from unbuffered, send
Does not block
Value received
Receive from buffered, not empty
Does not block
Value dequeued
Receive from buffered, empty
Blocks
N/A
Receive from closed, not empty
Does not block
Value dequeued
Receive from closed, empty
Does not block
Zero value, ok == false
6. Examples
Buffered Channel Receive After Close
goch := make(chan int, 2)ch <- 1ch <- 2close(ch)fmt.Println(<-ch) // 1fmt.Println(<-ch) // 2fmt.Println(<-ch) // 0, ok == false
Send to Closed Channel
goclose(ch)ch <- 1 // panic: send on closed channel
7. Non-blocking Operations
Use select with default:
goselect {case v := <-ch: // received valuedefault: // no value available, does not block}
Send-Only / Receive-Only
Create a bidirectional channel (e.g.,
ch := make(chan int)
)Pass as send-only or receive-only to functions
func sender(ch chan<- int) {
ch <- 42 // OK: can only send
// x := <-ch // ERROR: cannot receive
}
func receiver(ch <-chan int) {
x := <-ch // OK: can only receive
// ch <- 42 // ERROR: cannot send
}
ch := make(chan int)
go sender(ch) // send-only
go receiver(ch) // receive-only
Summary Table
chan T
Send & Receive
Both
chan<- T
Send only
ch <- v
<-chan T
Receive only
v := <-ch
Last updated