Skip to main content

Command Palette

Search for a command to run...

Interface: Pointers vs Values in Go

Updated
3 min read
Interface: Pointers vs Values in Go

Interfaces

An interface type is defined as a set of method signatures. A value of interface type can hold any value that implements those methods. Take a look at the below example taken from Go tour.

package main

import (
    "fmt"
    "math"
)

type Abser interface {
    Abs() float64
}

func main() {
    var a Abser
    f := MyFloat(-math.Sqrt2)
    v := Vertex{3, 4}

    a = f  // a MyFloat implements Abser
    a = &v // a *Vertex implements Abser

    // In the following line, v is a Vertex (not *Vertex)
    // and does NOT implement Abser.
    a = v

    fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Note: There is an error in the example code on line 22. Vertex (the value type) doesn't implement Abser because the Abs method is defined only on *Vertex (the pointer type).

But if i write func (v Vertex) abs() then also a = &v works! why?

In Go, when you define a method with a receiver type (like v *Vertex or v Vertex), the receiver can be a pointer or a value type. This distinction is important because it determines what can call the method.

The original case: func (v *Vertex) Abs()

In our original code, the Abs() method is defined with a pointer receiver:


func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

This means the method can only be called on a *Vertex (a pointer to a Vertex), not a Vertex itself.

  • When you do a = &v, you're assigning a pointer to v (*Vertex), which works fine because the method Abs() is defined on *Vertex, and so &v implements Abser.

However, when you do a = v (without the &), v is of type Vertex, not *Vertex. Since the method is defined on *Vertex, v does not implement the Abser interface, hence the error.

What happens if you change the method to (v Vertex) Abs()?

If you change the method signature to use a value receiver:


func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Now the method is defined on the Vertex type (the value type), so it can be called on both values of type Vertex and pointers of type *Vertex. This is because Go will automatically dereference the pointer for you.

  • If you have a value v of type Vertex, calling v.Abs() works.

  • If you have a pointer &v of type *Vertex, calling (&v).Abs() works too because Go automatically dereferences the pointer behind the scenes.

Why does a = &v work with a value receiver?

When the method is defined with a value receiver like this:


func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

It can be called on a pointer (*Vertex) as well. The reason is that Go will implicitly dereference the pointer when needed. So, even though the method expects a value (Vertex), you can still pass a pointer (*Vertex) because Go will automatically turn *v into v by dereferencing.

This implicit dereferencing works because a value receiver is less restrictive: the method doesn't modify the original struct (since it's a copy), so Go allows calling it on a pointer too, as it's safe!

More from this blog

D

Dushyanth

18 posts