Channels
A channel is a typed pipe for sending values between goroutines. msg := <-messages blocks until a value is sent on that channel, which is exactly how the two goroutines in the example below coordinate without any shared variable or lock.
main.go
Try it yourself →package main
import "fmt"
func main() {
messages := make(chan string)
go func() {
messages <- "hello from a goroutine"
}()
msg := <-messages
fmt.Println(msg)
}Output
hello from a goroutine
A real example: summing concurrently
sum runs as its own goroutine and sends its result back over result once it's done — main blocks on <-result until that value arrives. This channel-based handoff is Go's idiomatic alternative to manually sharing memory between goroutines and protecting it with locks.
main.go
Try it yourself →package main
import "fmt"
func sum(numbers []int, result chan<- int) {
total := 0
for _, n := range numbers {
total += n
}
result <- total
}
func main() {
result := make(chan int)
go sum([]int{1, 2, 3, 4, 5}, result)
fmt.Println(<-result)
}Output
15
Next: struct embedding — Go's way of building composition instead of class inheritance.
Practice exercise
Create a channel ch := make(chan string). Start a goroutine that sends "done" on ch, then receive and print the value from ch in main.