When defer func evaluates its parameters
Ok I just figured out. If you pass any parameters to the defer func (like the 2nd defer function above), those parameters are evaluated when the defer function is deferred, not when they are executed. That means in my example err
is still nil
and has not been assigned to a new error yet.
on the other hand, in 1st defer above, err
is not a parameter, but a variable in function a
, and when 1st defer is executed, it has already been assigned to a new error.
There is another similar situation there is in case of Defer Statement
and Defer Function
. Please have look at the example below
package main
import (
"fmt"
"time"
)
func main() {
start := time.Now()
time.Sleep(3*time.Second)
defer func() { fmt.Println("Defer Function Elapsed Time: ", time.Since(start)) }() //Defer Function
defer fmt.Println("Defer Statement Elapsed Time: ", time.Since(start)) //Defer Statement
time.Sleep(3*time.Second)
}
Output:
Defer Statement Elapsed Time: 3s
Defer Function Elapsed Time: 6s
Try above in go play
This is because of in the Deferred Statement
case the deferred call's arguments are evaluated immediately
refer doc
Another way is by using reference to original err variable
package main
import (
"errors"
"fmt"
)
func main() {
a()
}
func a() {
var err error
defer func() {
if err != nil {
fmt.Printf("1st defer: %s\n", err)
} else {
fmt.Println("1st defer: defer not error")
}
}()
defer func(err *error) {
if *err != nil {
fmt.Printf("2nd defer: %s\n", *err)
} else {
fmt.Println("2nd defer: defer not error")
}
}(&err)
err = errors.New("new error")
if err != nil {
return
}
}
And output is:
2nd defer: new error
1st defer: new error