Start learning free

LESSON 190 OF 338 · OBJECT-ORIENTED PROGRAMMING

Interfaces in Go: Implicit Contracts

Lesson Read the full explanation

TL ; DR:

An interface is a pure contract — a list of methods that a type promises to implement, with no shared data and no shared code. Unlike inheritance ("is a"), interfaces express "can do".


// Go uses an interface type listing the required methods:
type Speaker interface {
    speak()
}

type Dog struct{}

func (d Dog) speak() {
    fmt.Println("Woof")
}


Full lesson:

An interface defines what a type can do, not how it does it or what it is. A Truck, a Robot, and a Drone aren't the same kind of thing — but they can all Move(). You'd put Move() in a Movable interface and have each one implement it.

Interface vs abstract class

Abstract classInterface
Has fieldsYesUsually no
Has method bodiesYes (some)No (or default impls only)
Multiple "inheritance"Usually noYes — a class can implement many interfaces
Models"is a""can do"

A class inherits from at most one parent class but can implement many interfaces. That's why interfaces are the right tool for cross-cutting capabilities like Comparable, Serializable, Iterable, etc.

The language landscape

  • C# / Java — first-class interface keyword. C# uses : for both inheritance and implementation; Java uses extends for inheritance and implements for interfaces.
  • Python — no separate interface; abstract base classes (ABCs) with all-abstract methods serve the same role.
  • JavaScript — no interface keyword in plain JS (TypeScript has it). The convention is a stub class.
  • C++ — a class with only pure-virtual methods is an interface. Multiple inheritance lets a class implement several.

Your task

The Speaker interface (or interface-like base) is already declared. Create a Dog class that implements it, with a speak() method that prints "Woof".

Expected output:

Woof
STEP 1 OF 5
    Ctrl + Enter to check

    GO · OBJECT-ORIENTED PROGRAMMING

    Interfaces in Go, explained

    What an interface is

    An interface describes what a type can do, not what it is or how it does it. It is a list of method signatures. Any type that has all of those methods satisfies the interface, and code written against the interface works with every such type.

    A Truck, a Robot and a Drone have nothing in common as data, yet all three can move. A Movable interface with a single Move() method lets one function handle all of them. Inheritance answers "what kind of thing is this?"; an interface answers "what can I ask this to do?".

    Go has no classes and no inheritance. Behaviour is attached to ordinary types, usually structs, through methods, and interfaces are how different types are used interchangeably.

    Syntax

    An interface type lists the methods that are required:

    type Speaker interface {
        speak()
    }

    A type satisfies it by having a method with that name and signature. There is no implements keyword, and the type's declaration never mentions the interface:

    type Dog struct{}
    
    func (d Dog) speak() {
        fmt.Println("Woof")
    }

    This is called implicit satisfaction. The check happens where a value is used as the interface type. Because nothing links Dog to Speaker, you can define an interface after the types it describes, and one type can satisfy any number of interfaces without knowing about them.

    Using a value through the interface

    A variable of an interface type can hold any value whose type satisfies it. Calling a method on the variable runs the method of the type that is stored inside:

    type Cat struct{}
    
    func (c Cat) speak() {
        fmt.Println("Meow")
    }
    
    animals := []Speaker{Dog{}, Cat{}}
    for _, s := range animals {
        s.speak()
    }
    Woof
    Meow

    The loop is written against Speaker only. Adding a third type later changes nothing in the loop.

    Gotchas in Go

    • A missing method is a compile error. Assigning a Fish with no speak method to a Speaker variable fails with Fish does not implement Speaker (missing method speak). The error appears at the assignment, not at the type's declaration.
    • Receiver kind matters. If speak is declared with a pointer receiver, func (r *Robot) speak(), then only *Robot satisfies Speaker. Writing var s Speaker = Robot{} fails with method speak has pointer receiver; &Robot{} works. A value receiver, as Dog uses, is satisfied by both Dog and *Dog.
    • A nil interface has no method to call. var s Speaker holds nothing, so s == nil is true and s.speak() panics with a nil pointer dereference.
    • The signature must match exactly. A speak() string method does not satisfy an interface that asks for speak().
    • Interfaces carry no data. They list methods only. Shared fields belong in structs, which can be embedded in other structs.

    To see which concrete type is stored in an interface value, use a type assertion with the two-value form: d, ok := animals[0].(Dog) sets ok to true when the value is a Dog. With Printf, %T prints the dynamic type, for example main.Dog.

    The exercise, step by step

    The starter code already declares the Speaker interface. The task is to make a Dog that satisfies it and prints Woof.

    1. Declare Dog as an empty struct. It needs no fields, because the lesson only cares about behaviour.
    2. Add the speak method with a value receiver of type Dog. Declaring this method is what makes Dog satisfy Speaker. The receiver is named this here; Go code more commonly uses a short name such as d, but any name works and it has no special meaning.
    3. Print Woof inside the method with fmt.Println, which adds the newline.
    4. Define mainFunction with no parameters and no result, as a place to call the method through the interface.
    5. Declare rex with the interface type, var rex Speaker = Dog{}, and call rex.speak(). Typing the variable as Speaker rather than Dog means any other type with a speak() method could be put there without changing the calling code.
    type Speaker interface {
        speak()
    }
    
    type Dog struct {}
    
    func (this Dog) speak() {
        fmt.Println("Woof")
    }
    
    
    
    func mainFunction() {
        var rex Speaker = Dog{}
        rex.speak()
    }

    Running mainFunction prints:

    Woof

    Key takeaways

    • An interface is a set of method signatures; it has no fields and no method bodies.
    • A type satisfies an interface just by having the methods. Go has no implements keyword.
    • Calling a method on an interface variable runs the method of the stored concrete type.
    • Pointer receivers are only in the method set of the pointer type, so check which receiver your methods use.
    • A missing or mismatched method shows up as a compile error where the value is used as the interface.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free