I recently started learning GoLang. There have been multiple instances where the compiler throws an error when I try to pass variables as arguments inside Go functions. I've been able to debug this sometimes by using a pointer in front of the variable. Both &, and * pointers seem to clear the error. Though, I'd like to understand why. I'm wondering what the difference between &, and * is, and when each should be used. Thank you!
func (ctx *NewContext) SendNotification(rw http.ResponseWriter, req *http.Request, p httprouter.Params) {
decoder := json.NewDecoder(req.Body)
var u User
if err := decoder.Decode(&u); err != nil {
http.Error(rw, "could not decode request", http.StatusBadRequest)
return
}
}
In your example above you defined u as type User, but not a pointer to a User. So you need the &u because the Decode function in the json package is expecting an address or pointer.
If you created the instance of User like this: u := new(User) it would be a pointer since the new function returns a pointer. You could also create a pointer to a user like this: var u *User. If you did either of those, you would have to take out the &
in the call to Decode for it to work.
Pointers are basically variables that hold addresses. When you put the & in front of a variable it returns the address. The * could be read as 'redirect of'. So when you create a pointer like this:
var x *int
This can be read as x will redirect to an int. And when you assign a value to x you would give it an address like this: y := 10 x = &y
Where y is some int. So if you were to print out x, you would get the address of y, but if you printed out *x you would redirect to the what x points to which is y's value which is 10. If you were to print out &x, you would get the address of the pointer, x, itself.
If you tried to print out *y, which is just an int, not a pointer, it would throw an error because you would be redirecting with some value that is not an address to redirect to.
Run the below for some pointer fun:
package main
import "fmt"
func main() {
var y int
var pointerToY *int
var pointerToPointerToInt **int
y = 10
pointerToY = &y
pointerToPointerToInt = &pointerToY
fmt.Println("y: ", y)
fmt.Println("pointerToY: ", pointerToY)
fmt.Println("pointerToPointerToInt: ", pointerToPointerToInt)
fmt.Println("&y: ", &y) // address of y
fmt.Println("&pointerToY: ", &pointerToY)// address of pointerToY
fmt.Println("&pointerToPointerToInt: ", &pointerToPointerToInt) // address of pointerToPointerToInt
// fmt.Println(*y) throws an error because
// you can't redirect without an address..
// y only has int value of 10
fmt.Println("*pointerToY: ", *pointerToY) // gives the value of y
fmt.Println("*pointerToPointerToInt: ", *pointerToPointerToInt) // gives the value of pointerToY which is the address of y
fmt.Println("**pointerToPointerToInt: ", **pointerToPointerToInt) // this gives 10, because we are redirecting twice to get y
if pointerToY == *pointerToPointerToInt {
fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
}
if pointerToY == &y {
fmt.Println("'pointerToY == &y' are the same!")
}
if &pointerToY == pointerToPointerToInt {
fmt.Println("'&pointerToY == pointerToPointerToInt' are the same!")
}
if y == **pointerToPointerToInt {
fmt.Println("'y == **pointerToPointerToInt' are the same!")
}
if pointerToY == *pointerToPointerToInt {
fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
}
}
Hope this helps!
I will quote one smart dude:
& in front of variable name is used to retrieve the address of where this variable’s value is stored. That address is what the pointer is going to store.
* in front of a type name, means that the declared variable will store an address of another variable of that type (not a value of that type).
* in front of a variable of pointer type is used to retrieve a value stored at given address. In Go speak this is called dereferencing.
source: http://piotrzurek.net/2013/09/20/pointers-in-go.html
pointer
is used to point towards address
and it stores the memory address
Adding one example to help understand pointer
vs address
:
package main
import "fmt"
func main() {
var y int
var pointerToY *int
var x int
//var willThrowErrorVariable int
y = 10
pointerToY = &y
//willThrowErrorVariable = &y
x = *pointerToY
fmt.Println("y: ",y)
fmt.Println("y's address using pointerToY: ",pointerToY)
y = 4
fmt.Println("====================================================")
fmt.Println("Address of y after its value is changed: ",pointerToY)
fmt.Println("value of y using pointer after its value is changed: ",*pointerToY)
fmt.Println("Value of x after y value is changed: ",x)
}
output
y: 10
y's address using pointerToY: 0x414020
====================================================
Address of y after its value is changed: 0x414020
value of y using pointer after its value is changed: 4
Value of x after y value is changed: 10
As we can see, the value might change but the address
(&
) remains same and so the pointer
(*
) points to the value of address
.
In above example,
pointerToY
holds the pointer to refer address
of y
.x
holds the value which we pass to it using pointer
to address
of y
.y
, the x
still has 10
but if we try to access the value using pointer
to address
(pointerToY) , we get 4