What does this function return, and how does a deferred closure reach the named return value?
Read the snippet below. The function uses a named return value and a deferred closure that mutates it.
Determine the value increment() returns, and explain how the deferred closure reaches the named return value.
func increment() (result int) {
defer func() {
result++
}()
return 1
}
func main() {
fmt.Println(increment())
}
Predict the output.
It returns 2. With a named return value, return 1 assigns 1 to result, then the deferred closure runs and increments result to 2 before the function actually returns. A deferred closure can read and modify named return values after return is reached.
- ✗Thinking
return 1is final and the deferred closure cannot change the result - ✗Assuming this works with an unnamed return — only a named return value is mutable from
defer - ✗Believing the deferred closure runs before the
returnexpression is assigned, not after
- →How is this pattern used to convert a
panicinto a returnederror? - →Would the result change if the return value were unnamed?
What does this function return?
package main
import "fmt"
func increment() (result int) {
defer func() {
result++
}()
return 1
}
func main() {
fmt.Println(increment()) // 2
}
It returns 2. A return with a named value happens in two steps: return 1 first assigns result = 1, and only then do the deferred calls run. The closure sees that same result variable, increments it to 2, and that is the value the caller receives — after the deferred calls, the function returns the current result.
With an unnamed return (func() int) this trick would not work: the return value is copied at the return, and the deferred closure has no handle on it. This mechanism is the basis of the idiom that turns a panic into an error via recover() inside a defer.