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 tov(*Vertex), which works fine because the methodAbs()is defined on*Vertex, and so&vimplementsAbser.
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
vof typeVertex, callingv.Abs()works.If you have a pointer
&vof 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!






