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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With