Here is my code (run):
package main
import "fmt"
func main() {
var whatever [5]struct{}
for i := range whatever {
fmt.Println(i)
} // part 1
for i := range whatever {
defer func() { fmt.Println(i) }()
} // part 2
for i := range whatever {
defer func(n int) { fmt.Println(n) }(i)
} // part 3
}
Output:
0
1
2
3
4
4
3
2
1
0
4
4
4
4
4
Question: What's the difference between part 2 & part 3? Why part 2 output "44444" instead of "43210"?
I would like to address another example in order to improve the understanding of
defer mechanish
, run this snippet as it is first, then switch order of the statements marked as (A) and (B), and see the result to yourself.I keep wonderng what are the correct keywords or concepts to apply here. It looks like that the expression
c.method
is evaluated, thus returning a function binded to the actual state of the component "c" (like taking an snapshot of the component's internal state). I guess the answer involves not onlydefer mechanish
also howfuntions with value or pointer receiver
works. Do note that it also happens that if you change the func namedmethod
to be apointer receiver
the defer prints c.val as 2, not as 0.The 'part 2' closure captures the variable 'i'. When the code in the closure (later) executes, the variable 'i' has the value which it had in the last iteration of the range statement, ie. '4'. Hence the
part of the output.
The 'part 3' doesn't capture any outer variables in its closure. As the specs say:
So each of the defered function calls has a different value of the 'n' parameter. It is the value of the 'i' variable in the moment the defer statement was executed. Hence the
part of the output because:
The key point to note is that the 'f()' in 'defer f()' is not executed when the defer statement executes
but
the expression 'e' in 'defer f(e)' is evaluated when the defer statement executes.