package main import ( "fmt" "time" ) // A sender function that only sends values on the channel. // The channel type `chan<- string` ensures it can only be used for sending. func producer(messages chan<- string, done chan<- bool) { for i := 0; i < 3; i++ { msg := fmt.Sprintf("Message %d", i+1) fmt.Printf("Producer: Sending %s ", msg) messages <- msg time.Sleep(100 * time.Millisecond) } done <- true // Signal completion } // A receiver function that only receives values from the channel. // The channel type `<-chan string` ensures it can only be used for receiving. func consumer(messages <-chan string, done <-chan bool) { for { select { case msg := <-messages: fmt.Printf("Consumer: Received %s ", msg) case <-done: fmt.Println("Consumer: Producer finished.") return // Exit loop when done signal is received } } } func main() { messages := make(chan string) done := make(chan bool) go producer(messages, done) go consumer(messages, done) // Keep main goroutine alive to allow others to run time.Sleep(1 * time.Second) fmt.Println("Main: Application finished.") }