Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Please explain &, and * pointers

Tags:

pointers

go

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     } } 
like image 326
zero_cool Avatar asked Oct 01 '15 00:10

zero_cool


1 Answers

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!

like image 95
wueb Avatar answered Oct 04 '22 19:10

wueb