Learn Go← Dashboard

Go's duck typing: implicitly satisfied contracts.

Interface Basics

An interface is a list of method signatures. Any type that has those methods satisfies the interface — automatically, without declaring "I implement X".

This is "duck typing" with compile-time checks. It's the cleanest part of Go.

Defining an interface

type Animal interface {
    Speak() string
}

Any type that has a Speak() string method is — at the type-system level — an Animal. No implements keyword, no inheritance.

Implicit satisfaction

go playground
Loading...

Dog and Cat never mention Animal. The compiler checks the method set at the call site.

A real-world example: io.Writer

io.Writer is one method:

type Writer interface {
    Write(p []byte) (n int, err error)
}

Everything in Go that writes bytes is an io.Writer — files, network sockets, buffers, HTTP responses. Once you write a function that takes io.Writer, it works with all of them.

go playground
Loading...

Keep interfaces small

The Go proverb says: "the bigger the interface, the weaker the abstraction." The smallest interfaces (one or two methods) are the most reusable. Define them on the consumer side — i.e. write the interface where you use it, not where you implement it.

The nil-interface gotcha

An interface value has two parts: a type and a value. It's nil only when both are nil. This bites people:

func boom() error {
    var p *MyError = nil
    return p          // returns a non-nil error whose value is nil!
}

if err := boom(); err != nil {   // ← this is TRUE
    log.Println(err)
}

The interface knows about the type *MyError, even though the value is nil — so err == nil is false. Fix: return nil directly when there's no error.

To satisfy `io.Writer`, a type needs…