DEV Community

Shaikhul Islam
Shaikhul Islam

Posted on

Pointers in Go

Go is a call-by-value language, meaning it will use a copy of each function arguments in function calls, if we want to update a variable we need to pass its address using a pointer.

Go pointer syntax are similar as C.

Pointer basics
Get address of a variable using & operator
Derefence using pointer * operator

// int variable
year := 2020
// we can get address using & op
year_add := &year
fmt.Println("Val of year: ", year)
fmt.Println("Address of year: ", &year)
fmt.Println("Val of year using pointer: ", *(&year))
Enter fullscreen mode Exit fullscreen mode

Function call by value

func call_by_val(year int) {
  year = year + 1
}
call_by_val(year)
// year won't be updated as it uses a copy in call_by_val function
fmt.Println("Call by val res: ", year)
Enter fullscreen mode Exit fullscreen mode

Function call by reference

func call_by_ref(year *int) {
  *year = *year + 1
}
call_by_ref(&year)
// here it will update the variable as we pass the address of the variable
fmt.Println("Call by ref res: ", year)
Enter fullscreen mode Exit fullscreen mode

Method with Pointer Receiver
When using pointer receiver in methods, Go compiler does implicit conversion to match the type of receiver argument with receiver parameter.
To explain different use cases I will use a Point type and some methods as follows

type Point struct {
  X, Y int
}
func (p *Point) Scale(factor int) {
  p.X = p.X * factor
  p.Y = p.Y * factor
}
// pointer receiver param
func (p *Point) Print() {
  fmt.Println("X: ", p.X, ", Y: ", p.Y)
}

// receiver param of type Point, any change won't be reflected on receiver argument
func (p Point) ScaleVal(factor int) {
  p.X = p.X * factor
  p.Y = p.Y * factor
}

// value receiver param
func (p Point) PrintP() {
  fmt.Println("X: ", p.X, ", Y: ", p.Y)
}
Enter fullscreen mode Exit fullscreen mode
  • Use case 1: both uses same pointer type No implicit conversion
p := Point{X:2, Y:3}
p_ptr := &p
Scale(p_ptr, 2)
// this will print the scaled point
Print(p_ptr)
Enter fullscreen mode Exit fullscreen mode
  • Use case 2: receiver param is of type pointer
// receiver arg is of type Point, compiler implicitly get &p to match type with receiver param
p.Scale(2)
p.Print()
Enter fullscreen mode Exit fullscreen mode
  • User case 3: receiver argument is of type pointer
// receiver param is of type Point but receiver arg is a pointer, compiler dereference the receiver but any mutation won't be reflected on receiver arg
p_ptr.ScaleVal(2)
p_ptr.PrintP()
Enter fullscreen mode Exit fullscreen mode

Here is the full example in repl.it

Top comments (0)