Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand `defer` in go language?

Tags:

go

In the godoc(https://blog.golang.org/defer-panic-and-recover), there is an example:

  1. 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 ?

like image 876
BlackMamba Avatar asked Dec 24 '22 23:12

BlackMamba


1 Answers

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())
}
like image 186
Blixt Avatar answered Jan 06 '23 11:01

Blixt