Reputation: 10254
In the godoc(https://blog.golang.org/defer-panic-and-recover), there is an example:
- Deferred functions may read and assign to the returning function's named return values.
In this example, a deferred function increments the return value i after the surrounding function returns. Thus, this function returns 2:
func c() (i int) {
defer func() { i++ }()
return i
}
I also wrote a small progam:
package main
import "fmt"
func b() int {
i := 0
for ; i < 4; i++ {
defer func() {fmt.Println(i); i++} ()
}
return i
}
func main() {
fmt.Println("result = ", b())
}
the output is:
4
5
6
7
result = 4
So I am confused, why does the second example not output 8
?
Upvotes: 5
Views: 1534
Reputation: 314
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns.
Your func b() is semantically equivalent to:
func b() int {
i := 0
for ; i < 4; i++ {
}
ret := i
fmt.Println(i); i++
fmt.Println(i); i++
fmt.Println(i); i++
fmt.Println(i); i++
return ret
}
Ergo b() returns 4.
Upvotes: 0
Reputation: 50169
Note the part that says "may read and assign to the returning function's named return values."
This means that:
func b() int {
var i int
defer func() { fmt.Println(i); i++ }()
return i
}
will say 0
and result = 0
, while:
func b() (i int) {
defer func() { fmt.Println(i); i++ }()
return i
}
will say 0
and result = 1
.
It might help to imagine that the return i
in my first example assigns the i
value to a hidden return variable (because it's not named), then goes on to execute the defer
statements (which only modify the local variable i
), while in the second example we assign directly to the return variable (because it's named) and so the defer
statement is able to change it.
Basically your program could be interpreted like this:
package main
import "fmt"
func b() (hiddenVariable int) {
i := 0
for ; i < 4; i++ {
defer func() { fmt.Println(i); i++ }()
}
hiddenVariable = i; return // implicit meaning of return i
}
func main() {
fmt.Println("result = ", b())
}
Upvotes: 10
Reputation: 1
Based solely on what I learned about defer and after looking at your code, I'd like to say that the for loop defers the print out of subsequent 'i's until later, however, the for loop still runs and therefore affects the 'i' returned by func b(), which is 4.
for ; i < 4; i++ {
defer func() {fmt.Println(i); i++} ()
}
return i
Because the print statement and it's 'value' for 'i' is deferred, they increment beyond 4, but the 'i' after the for loop remains at 4.
Upvotes: 0