Lesson 9 / 26

Interfaces

Implicit satisfaction, small contracts.

Behaviour, not hierarchy

An interface lists method signatures; any type that has those methods satisfies it implicitly, with no implements keyword. This decouples code: a function accepting io.Reader works with files, network connections and buffers. Keep interfaces small (one or two methods), define them where they are used, and accept interfaces but return concrete types. A type assertion (v.(Circle)) or type switch recovers the concrete type; fmt.Stringer (a String() string method) controls how a value prints.

Shapes through one interface, run

I ran this with Go 1.27.1 (go run . in a module named demo, standard library only). Rect and Circle both satisfy Shape just by having an Area method; total sums their areas (12 + pi). Circle's String method controls printing, and a type assertion recovers the concrete Circle.

package main

import (
	"fmt"
	"math"
)

type Shape interface {
	Area() float64
}

type Rect struct{ W, H float64 }
type Circle struct{ R float64 }

func (r Rect) Area() float64   { return r.W * r.H }
func (c Circle) Area() float64 { return math.Pi * c.R * c.R }
func (c Circle) String() string { return fmt.Sprintf("Circle(r=%v)", c.R) } // fmt.Stringer

func total(shapes []Shape) float64 {
	sum := 0.0
	for _, s := range shapes {
		sum += s.Area()
	}
	return sum
}

func main() {
	shapes := []Shape{Rect{3, 4}, Circle{1}} // no "implements" keyword needed
	fmt.Printf("total area: %.2f\n", total(shapes))
	fmt.Println(shapes[1])
	if c, ok := shapes[1].(Circle); ok { // type assertion
		fmt.Println("radius:", c.R)
	}
}

Output:

total area: 15.14
Circle(r=1)
radius: 1

Define interfaces at the consumer

Declare the small interface you need next to the code that uses it, rather than large interfaces next to implementations.

Quick check: How does a Go type satisfy an interface?

  • By embedding the interface name in its struct
  • With an implements clause
  • By having all the interface's methods; no declaration is needed
  • By registering in go.mod
Answer

By having all the interface's methods; no declaration is needed — Satisfaction is implicit.