Reputation: 9119
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
Reputation: 625
Just use return value and assign.
func nilSetter(x *int) *int {
x = nil
return x
}
x = nilSetter(x)
Upvotes: 0
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
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