Today we finish the description of go statements:
Go statements
… When the function terminates, its goroutine also terminates. If the function has any return values, they are discarded when the function completes.
go Server() go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)
Okay, so that bit about discarding return values makes sense, right?
func main() {
go sum(1, 3) // return value discarded
}
func sum(a, b int) int {
return a + b
}
But what if you need that return value for something?
Well, then you need to set up some extra plumbing:
func main() {
var a int
go func() {
a = sum(1, 3)
}()
fmt.Println(a)
}
The return value is no longer discarded. However, this code suffers from another problem: We don’t wait for the new goroutine to finish before we print out the value of the variable a
. This means that the program is likely (though not guaranteed) to print 0
, rather than the expected 4
.
To accomodate this, we’d need to introduce some mechanism to wait for the goroutine to finish first. There are many ways to do this, and of course in a toy example like this, any of them render the goroutine pretty moot. But here’s one simple approach:
func main() {
var a int
done := make(chan struct{}, 0)
go func() {
a = sum(1, 3)
close(done)
}()
<- done
fmt.Println(a)
}
This example creates a channel, done
, which is closed when the new goroutine is ready to exit. Then the main goroutine waits for a value on that channel with <- done
. Closing the channel will cause this to return a nil value—we don’t care what value we get, just that we get some value, before continuing, and displaying the result of the sum
function.
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)