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))

  • 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))

  • 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

Scenario
Blocking?
What is Returned / Happens

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

Channel Type
Allowed Operation
Example

chan T

Send & Receive

Both

chan<- T

Send only

ch <- v

<-chan T

Receive only

v := <-ch

Last updated