Amir Keibi
Amir Keibi

Reputation: 2144

Data passed by reference to "defer"

There is a passage in the "Mastering Concurrency in Go" book which made me think I might be missing something about "defer" functions.

You should also take note that any data passed by reference may be in an unexpected state.

func main() {
    aValue := new(int)
    defer fmt.Println(*aValue)

    for i := 0; i < 100; i++ {
         *aValue++
    }
}

This prints 0, I thought, because according to spec:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew

That is, *aValue is 0 when defer is called and that's why at the end it prints 0. Whether or not a pointer is passed to the differ function in this case is irrelevant.

Is my understanding correct or am I missing something?

Upvotes: 2

Views: 1555

Answers (2)

AJcodez
AJcodez

Reputation: 34236

Consider a situation using structs.

type User struct {
    Name string
}

func main() {
    user := User{}
    defer fmt.Printf("%#v\n", user)
    user.Name = "AJ"
}

You know defer should run at the end, so you might expect to see User{Name: "AJ"} but instead you get User{Name: ""} because defer binds parameters.

If you use a pointer it works.

    user := &User{}

If you use a closure, it works.

    defer func() {
        fmt.Printf("%#v\n", user)
    }()

Upvotes: 3

dalton_c
dalton_c

Reputation: 7170

The defer statement is "evaluating" the parameters and saving the result, and the result of evaluating *aValue is 0 at the time of the defer call. Something like this may be what you're looking for:

func main() {
    aValue := new(int)
    defer func() { fmt.Println(*aValue) }()

    for i := 0; i < 100; i++ {
        *aValue++
    }
}

Upvotes: 2

Related Questions