Introduction to Interfaces
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 25 of 107.
An interface in Go defines a set of method signatures without implementing them. It describes what a type can do, not how it does it. Any type that implements all the methods in an interface automatically satisfies that interface.
Here's how you define an interface:
type Speaker interface {
Speak() string
}This Speaker interface requires any implementing type to have a Speak() method that returns a string. Now any struct with this method can be used wherever a Speaker is expected.
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " says woof!"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return c.Name + " says meow!"
}Both Dog and Cat satisfy the Speaker interface because they each have a Speak() method with the correct signature. You can now write functions that accept any Speaker:
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Buddy"}
cat := Cat{Name: "Whiskers"}
MakeSound(dog) // Buddy says woof!
MakeSound(cat) // Whiskers says meow!
}Interfaces enable you to write flexible, reusable code that works with any type meeting the interface's requirements, regardless of the underlying implementation.
Challenge
EasyLet's build a vehicle description system that demonstrates how interfaces allow different types to share common behavior. You'll create an interface that multiple vehicle types can satisfy, then use it to describe any vehicle uniformly.
You'll organize your code across two files:
vehicles.go: Define aDescriberinterface with a single methodDescribe() string. Then create two structs that satisfy this interface:CarwithBrandandModelfields (both strings)BicyclewithType(string) andGears(int) fields
Describe()method that returns a descriptive string about the vehicle.main.go: Create a function calledPrintDescriptionthat accepts anyDescriberand prints the result of calling itsDescribe()method. Read vehicle information from input, create both a Car and a Bicycle, and use your function to print descriptions for each.
The following inputs will be provided:
- Line 1: Car brand
- Line 2: Car model
- Line 3: Bicycle type
- Line 4: Number of gears (integer)
Your Describe() methods should return strings in these formats:
- Car:
[Brand] [Model] - Bicycle:
[Type] bike with [Gears] gears
For example, given Toyota, Camry, Mountain, and 21, your output should be:
Toyota Camry
Mountain bike with 21 gearsThe key insight is that your PrintDescription function works with any type that has a Describe() method—it doesn't need to know whether it's dealing with a Car, Bicycle, or any other vehicle type you might add later.
Cheat sheet
An interface in Go defines a set of method signatures without implementing them. Any type that implements all the methods automatically satisfies that interface.
Defining an interface:
type Speaker interface {
Speak() string
}Types that implement the required methods satisfy the interface:
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " says woof!"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return c.Name + " says meow!"
}Functions can accept any type that satisfies the interface:
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Buddy"}
cat := Cat{Name: "Whiskers"}
MakeSound(dog) // Buddy says woof!
MakeSound(cat) // Whiskers says meow!
}Try it yourself
package main
import (
"fmt"
)
// TODO: Create a PrintDescription function that accepts any Describer
// and prints the result of calling its Describe() method
func main() {
// Read input
var carBrand string
var carModel string
var bicycleType string
var gears int
fmt.Scanln(&carBrand)
fmt.Scanln(&carModel)
fmt.Scanln(&bicycleType)
fmt.Scanln(&gears)
// TODO: Create a Car with the brand and model from input
// TODO: Create a Bicycle with the type and gears from input
// TODO: Use PrintDescription to print the description of the car
// TODO: Use PrintDescription to print the description of the bicycle
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool