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
Fishwith nospeakmethod to aSpeakervariable fails withFish does not implement Speaker (missing method speak). The error appears at the assignment, not at the type's declaration. - Receiver kind matters. If
speakis declared with a pointer receiver,func (r *Robot) speak(), then only*RobotsatisfiesSpeaker. Writingvar s Speaker = Robot{}fails withmethod speak has pointer receiver;&Robot{}works. A value receiver, asDoguses, is satisfied by bothDogand*Dog. - A nil interface has no method to call.
var s Speakerholds nothing, sos == nilis true ands.speak()panics with a nil pointer dereference. - The signature must match exactly. A
speak() stringmethod does not satisfy an interface that asks forspeak(). - 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.
- Declare
Dogas an empty struct. It needs no fields, because the lesson only cares about behaviour. - Add the
speakmethod with a value receiver of typeDog. Declaring this method is what makesDogsatisfySpeaker. The receiver is namedthishere; Go code more commonly uses a short name such asd, but any name works and it has no special meaning. - Print
Woofinside the method withfmt.Println, which adds the newline. - Define
mainFunctionwith no parameters and no result, as a place to call the method through the interface. - Declare
rexwith the interface type,var rex Speaker = Dog{}, and callrex.speak(). Typing the variable asSpeakerrather thanDogmeans any other type with aspeak()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
implementskeyword. - 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.