Kenenbek Arzymatov
Kenenbek Arzymatov

Reputation: 9119

Set pointer to nil via function

There is a function that sets a pointer to a nil value:

func nilSetter(x *int) {
    x = nil
}

I have such snippet of code:

i := 42
fmt.Println(&i)
nilSetter(&i)
fmt.Println(&i)

Which prints:

0xc42008a000
0xc42008a000

While I expect:

0xc42008a000
nil

I know that it happens because function nilSetter just copy address and sets to nil that copy.

But how can I do it correctly?

Upvotes: 3

Views: 8604

Answers (3)

F566
F566

Reputation: 625

Just use return value and assign.

func nilSetter(x *int) *int {
    x = nil
    return x
}

x = nilSetter(x)

Upvotes: 0

maksadbek
maksadbek

Reputation: 1592

The reason of such behaviour is because there is no pass by reference in Go.

Two variables can have contents that point to the same storage location. But, it is not possible to have them share the same storage location. Example:

package main

import "fmt"

func main() {
        var a int
        var b, c = &a, &a
        fmt.Println(b, c)   // 0x1040a124 0x1040a124
        fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}

From your code, the argument x of nilSetter is pointing to some location but it have its own address and when you are setting a nil to it, you are changing its address not the address of what it is pointing to.

package main

import "fmt"

func nilSetter(x *int) {
    x = nil
    fmt.Println(x, &x) // <nil> 0x1040c140
}

func main() {
    i := 42
    fmt.Println(&i) // 0x10414020
    nilSetter(&i)
    fmt.Println(&i) // 0x10414020
}

That is why pointers always have an exact address even its value is nil

Referencing to a blog post by Dave Cheney: https://dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go

Upvotes: 3

Not_a_Golfer
Not_a_Golfer

Reputation: 49205

The only way to achieve that is with a pointer to a pointer. And it's pretty clunky so it's probably not what you want:

func nilSetter(x **int) {
    *x = nil
}

func main() {
    x := 2
    xp := &x

    fmt.Println(xp)
    nilSetter(&xp)
    fmt.Println(xp)

}

// Output:
// 0x10414020
// <nil>

Upvotes: 2

Related Questions