To create an unbuffered channel, call the function make()
without specifying the channel capacity:
var iChan chan int = make(chan int) // channel for data type int
sChan := make(chan string) // channel for data type string
If the channel is empty, the receiver goroutine is blocked until there is data in the channel. When the sender goroutine sends data, The recipient goroutine receives this data and resumes work.
The sender goroutine can only send data to an empty channel. The sender goroutine is blocked until the data from the channel is received. For example:
package main
import "fmt"
func main() {
iChan:= make(chan int)
go func(){
fmt.Println("starts")
iChan<- 2024 // Block until the data is retrieved by the main function
}()
fmt.Println(<-iChan) // Retrieving data from channel
fmt.Println("Done!")
}
Through the unbuffered channel iChan
, the goroutine, represented by an anonymous function, transmits the number 2024:
iChan<- 2024
The main function gets this number:
fmt.Println(<-iChan)
The general flow of the program looks like this:
iChan
channel and runs the goroutine as an anonymous function.fmt.Println(<-iChan)
until data is received.In this case, the goroutine is defined as an anonymous function and therefore it has access to the environment, including the iChan variable. If we work with ordinary functions, then channel objects must be passed through the parameters:
package main
import "fmt"
func main() {
iChan := make(chan int)
go printHello(5, iChan) // Start a goroutine
for i := 0; i < 5; i++ {
fmt.Println(<-iChan) // Receive data from the channel for each iteration
}
fmt.Println("Done")
}
func printHello(n int, ch chan int) {
for i := 1; i <= n; i++ {
ch <- i // Sending the current value of i to the channel
fmt.Println(i, "-", "Hello World")
}
}
Note how the parameter that represents the data channel of type int: is defined ch chan int. Console output of this program:
1 - Hello World
1
2
2 - Hello World
3 - Hello World
3
4
4 - Hello World
5 - Hello World
5
Done