These two ideas are closely related. The easiest mental model is:
Interface = a list of behaviors.
Implicit implementation = Go automatically accepts any type that has those behaviors.
You never write implements in Go.
1. Interfaces
What is an interface?
An interface describes what something can do, without saying how it does it.
For example:
type Speaker interface {
Speak() string
}
This means:
Anything that has a method
Speak() stringcan be treated as aSpeaker.
The interface does not contain the implementation.
Why use interfaces?
Interfaces help you write code that works with different types without caring about their exact type.
Imagine:
- Dog can speak
- Person can speak
- Robot can speak
Your program doesn’t necessarily need to know whether something is a Dog, Person, or Robot.
It only needs to know:
“Can this thing
Speak()?”
Complete Example — Interface
Copy and run:
package main
import "fmt"
// Speaker describes a behavior.
//
// Any type that has:
// Speak() string
//
// can be used as a Speaker.
type Speaker interface {
Speak() string
}
// Dog is a normal struct.
type Dog struct {
Name string
}
// Dog has the Speak method.
func (d Dog) Speak() string {
return d.Name + " says Woof!"
}
// Person is another normal struct.
type Person struct {
Name string
}
// Person also has the Speak method.
func (p Person) Speak() string {
return p.Name + " says Hello!"
}
// This function does NOT care
// whether it receives Dog, Person, etc.
//
// It only requires something
// that satisfies the Speaker interface.
func makeItSpeak(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Buddy"}
person := Person{Name: "John"}
makeItSpeak(dog)
makeItSpeak(person)
}
Output:
Buddy says Woof!
John says Hello!
Understand the important part
Look at this:
type Speaker interface {
Speak() string
}
The interface says:
I need something with Speak() string
Then:
func (d Dog) Speak() string
Dog has that method.
And:
func (p Person) Speak() string
Person also has that method.
Therefore both can be passed here:
func makeItSpeak(s Speaker)
What happened?
Conceptually:
flowchart TD
A["Speaker interface"] --> B["Requires: Speak() string"]
C["Dog"] --> D["Has Speak() string"]
E["Person"] --> F["Has Speak() string"]
D --> G["Can be used as Speaker"]
F --> G
Why is this useful?
Without the interface, you might write:
func makeDogSpeak(d Dog) {
fmt.Println(d.Speak())
}
func makePersonSpeak(p Person) {
fmt.Println(p.Speak())
}
With an interface:
func makeItSpeak(s Speaker) {
fmt.Println(s.Speak())
}
One function works with many different types.
When should I use an interface?
Use an interface when several types should be usable through the same behavior.
For example:
Writer
Write()
Reader
Read()
Notifier
Notify()
PaymentProcessor
Pay()
Storage
Save()
Speaker
Speak()
Think:
“I don’t care exactly WHAT you are. I care about WHAT YOU CAN DO.”
Where are interfaces commonly used?
You’ll see them in:
- function parameters
- testing and mocks
- database abstractions
- HTTP code
- file handling
- logging
- external services
- application architecture
For a beginner, the most important use is:
func doSomething(x SomeInterface)
It allows different types to be passed to the same function.
2. Implicit Interface Implementation
This is one of the most important differences between Go and languages such as Java.
In Go, you do not explicitly declare that a type implements an interface.
Go checks the methods automatically.
The key rule
Suppose we have:
type Notifier interface {
Notify()
}
And:
type Email struct{}
func (e Email) Notify() {
fmt.Println("Sending email")
}
Go automatically knows:
Email has Notify()
Notifier requires Notify()
Therefore:
Email satisfies Notifier
There is no:
implements Notifier
That is why it is called implicit interface implementation.
Complete Example — Implicit Interface Implementation
Copy and run:
package main
import "fmt"
// Notifier says:
// "Any type with Notify() can be a Notifier."
type Notifier interface {
Notify()
}
// Email is just a normal struct.
type Email struct {
Address string
}
// Email has the method required by Notifier.
//
// Notice:
// We NEVER wrote:
// Email implements Notifier
//
// Go figures it out automatically.
func (e Email) Notify() {
fmt.Println("Sending email to:", e.Address)
}
// SMS is another normal struct.
type SMS struct {
Phone string
}
// SMS also has Notify().
//
// Therefore SMS ALSO automatically
// satisfies the Notifier interface.
func (s SMS) Notify() {
fmt.Println("Sending SMS to:", s.Phone)
}
// sendNotification accepts ANY type
// that satisfies Notifier.
func sendNotification(n Notifier) {
n.Notify()
}
func main() {
email := Email{
Address: "john@example.com",
}
sms := SMS{
Phone: "1234567890",
}
sendNotification(email)
sendNotification(sms)
}
Output:
Sending email to: john@example.com
Sending SMS to: 1234567890
What exactly makes Email a Notifier?
The interface requires:
type Notifier interface {
Notify()
}
Email has:
func (e Email) Notify()
So Go says:
Notifier requirement
↓
Notify()
↑
Email has Notify()
↓
Email satisfies Notifier
Nothing else is required.
There is no implements
This is the part worth remembering.
In some languages you might see something conceptually like:
class Email implements Notifier
Go does not work like that.
You simply write:
type Email struct{}
and:
func (e Email) Notify() {
fmt.Println("Email sent")
}
That’s enough.
Go notices that the method matches the interface.
How does Go decide?
Go compares the interface’s required methods with the type’s methods.
Example:
type Notifier interface {
Notify()
}
Type A:
type Email struct{}
func (Email) Notify() {}
✅ Implements Notifier.
Type B:
type SMS struct{}
func (SMS) Notify() {}
✅ Implements Notifier.
Type C:
type Car struct{}
func (Car) Drive() {}
❌ Does NOT implement Notifier.
Why?
Because Car has:
Drive()
but the interface requires:
Notify()
What if an interface has multiple methods?
Then the type must have all of them.
For example:
type Device interface {
Start()
Stop()
}
This satisfies it:
type Computer struct{}
func (Computer) Start() {}
func (Computer) Stop() {}
But this does not:
type Computer struct{}
func (Computer) Start() {}
because:
Start() ✅
Stop() ❌
All required methods must exist.
Interfaces vs Implicit Implementation
| Concept | Interface | Implicit Implementation |
|---|---|---|
| What is it? | Defines required behaviors | Determines whether a type satisfies an interface |
| Example | type Speaker interface { Speak() } | Dog has Speak(), so Dog satisfies Speaker |
| Contains data? | No | Not applicable |
| Contains required methods? | Yes | Type must provide those methods |
Need implements keyword? | No | No |
| Checked by Go? | Yes | Yes |
| Main purpose | Define behavior | Connect types to interfaces automatically |
| Think of it as | “What must you do?” | “You can already do it, so you qualify.” |
Interface vs Struct
This distinction is also important.
| Struct | Interface |
|---|---|
| Describes data | Describes behavior |
| Contains fields | Contains method requirements |
Name string | Speak() string |
| Represents what something is | Represents what something can do |
| Usually creates concrete values | Usually used to accept multiple types |
Example struct:
type Dog struct {
Name string
Age int
}
This describes data.
Example interface:
type Speaker interface {
Speak() string
}
This describes behavior.
The relationship between everything
flowchart TD
A["Interface"] --> B["Defines required methods"]
B --> C["Speak() string"]
D["Dog"] --> E["Has Speak() string"]
F["Person"] --> G["Has Speak() string"]
H["Car"] --> I["Has Drive()"]
E --> J["Satisfies Speaker"]
G --> J
I --> K["Does NOT satisfy Speaker"]
J --> L["Can be passed to function expecting Speaker"]
The Mental Model
Don’t think:
Dog IS a Speaker
Instead think:
Dog CAN Speak
Therefore:
Dog can be USED AS a Speaker.
That is very close to how Go interfaces are intended to be understood.
What → Why → When → How → Where
| Question | Answer |
|---|---|
| What? | An interface defines methods that a type must have |
| Why? | So one piece of code can work with many different types |
| When? | When different types share the same behavior |
| How? | Define an interface and give types matching methods |
| Where? | Commonly in function parameters, libraries, services, testing and abstractions |
For implicit implementation:
| Question | Answer |
|---|---|
| What? | Automatic interface satisfaction |
| Why? | Removes explicit implements declarations |
| When? | Whenever a type’s methods match an interface |
| How? | Simply implement all required methods |
| Where? | Everywhere interfaces are used in Go |
The 5 Rules to Remember
- An interface describes behavior.
type Speaker interface {
Speak()
}
- A type satisfies an interface by having all required methods.
func (Dog) Speak() {}
- There is no
implementskeyword.
You never write:
Dog implements Speaker
- Multiple unrelated types can satisfy the same interface.
Dog → Speak()
Person → Speak()
Robot → Speak()
All three can satisfy Speaker.
- Functions can accept the interface instead of the concrete type.
func talk(s Speaker) {
s.Speak()
}
Now talk() can work with every compatible type.
One-Sentence Summary
The entire concept can be reduced to:
An interface says “I need these methods”; any Go type that has those methods automatically satisfies the interface.
So whenever you see:
type X interface {
DoSomething()
}
read it mentally as:
“Give me anything that knows how to
DoSomething().”
That mental model will make Go interfaces much easier to understand.