Sunday, August 1, 2021
What's the output of the following program?
package main
import (
"fmt"
)
func foo() (result string) {
defer func () { fmt.Printf("foo result = %q\n", result) }()
return "hi"
}
func bar() (result string) {
defer fmt.Printf("bar result = %q\n", result)
return "hi"
}
func main() {
fmt.Printf("foo() = %q\n", foo())
fmt.Printf("bar() = %q\n", bar())
}
First foo
is executed, which will print something, and then the first line of
main
will print something.
Then bar
is executed, which will print something, and then the second line
of main
will print something.
Here's the output:
foo result = "hi"
foo() = "hi"
bar result = ""
bar() = "hi"
Does the third line surprise you? It sure surprised me. Go ahead, try it yourself.
Reading StackOverflow didn't help. Instead, I had to read the language specification, which is what I ought always to do.
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.
The parameters are evaluated when the defer statement executes, not when the deferred function is invoked.
This is confusing, because one way to defer code is to wrap it in a closure
(func
) and invoke the closure later on.
Go's defer
statement is more general. After thinking about it, I prefer the
Go way, except that now I have this hole in my foot.
Be careful out there.