Skip to content

Interfaces

An interface is a named collection of method signatures. Any type that has all of those methods satisfies the interface — without saying so explicitly.

type Shape interface {
Area() float64
Perimeter() float64
}

Any type with an Area() float64 method and a Perimeter() float64 method automatically satisfies Shape.

This is the defining feature of Go interfaces. Compare:

LanguageHow you declare satisfaction
Java / C#class Circle implements Shape
GoJust have the right methods

The result is decoupled code. A type in package geometry can satisfy an interface in package renderer without either package knowing about the other. This makes Go interfaces composable across package boundaries without any import dependency on the interface definition.

Go’s standard library is built on tiny, focused interfaces:

type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }
type Stringer interface { String() string }

The Go proverb: “The bigger the interface, the weaker the abstraction.” A two-method interface is satisfied by far more types than a ten-method interface, making it dramatically more reusable.

An interface with no methods is satisfied by every type. Since Go 1.18 it has the alias any:

var v any = 42
v = "hello"
v = []int{1, 2, 3}

Use any sparingly — it surrenders type safety. The typical use cases are generic containers (before generics were added), JSON unmarshalling into unknown shapes, and variadic logging functions.

The idiomatic Go guideline:

  • Function parameters should be interfaces — accept the broadest type that covers what you actually call.
  • Return values should be concrete structs — callers get the full API of the real type; they can narrow it themselves.
// Good: accepts an interface, returns a concrete type
func NewBuffer(r io.Reader) *bytes.Buffer { ... }
package main
import (
"fmt"
"math"
)
type Shape interface {
Area() float64
Perimeter() float64
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
type Rect struct {
W, H float64
}
func (r Rect) Area() float64 { return r.W * r.H }
func (r Rect) Perimeter() float64 { return 2 * (r.W + r.H) }
func describe(s Shape) {
fmt.Printf("area=%.2f perimeter=%.2f\n", s.Area(), s.Perimeter())
}
func main() {
shapes := []Shape{
Circle{Radius: 5},
Rect{W: 4, H: 3},
}
for _, s := range shapes {
describe(s)
}
}
How does a Go type declare that it implements an interface?
You define an interface `Printer` with one method in package `ui`. A struct `Document` in package `doc` has that method. What import is needed?
What does `any` mean in Go 1.18+?
Your function needs to write bytes. Which parameter type is most idiomatic?