If it walks like a duck and quacks like a duck, Go treats it like a duck. Interfaces in Go are satisfied implicitly, creating loose coupling and high testability across packages.
TL;DR (Quick Summary)#
- Implicit Satisfaction: If a struct implements the methods of an interface, it implements the interface automatically.
- Interface Composition: Interfaces can embed other interfaces (e.g.
io.ReadWriterembedsio.Readerandio.Writer). any(Empty Interfaceinterface{}): Represents a value of any type.- Type Assertion (
v, ok := i.(T)): Extracts the concrete underlying value safely.
1. Interface Polymorphism Example#
package main
import "fmt"
// Interface declaration
type Notifier interface {
Notify(message string) error
}
// Concrete Type 1
type EmailNotifier struct {
Email string
}
func (e EmailNotifier) Notify(msg string) error {
fmt.Printf("Sending Email to %s: %s\n", e.Email, msg)
return nil
}
// Concrete Type 2
type SMSNotifier struct {
PhoneNumber string
}
func (s SMSNotifier) Notify(msg string) error {
fmt.Printf("Sending SMS to %s: %s\n", s.PhoneNumber, msg)
return nil
}
// Polymorphic Function accepting ANY Notifier
func SendAlert(n Notifier, alertMsg string) {
n.Notify(alertMsg)
}
func main() {
email := EmailNotifier{Email: "admin@work.com"}
sms := SMSNotifier{PhoneNumber: "+123456789"}
SendAlert(email, "Server Disk Full!")
SendAlert(sms, "CPU Spiked to 99%!")
}2. Type Assertions & Type Switches#
package main
import "fmt"
func ProcessValue(val any) {
// 1. Type Switch
switch v := val.(type) {
case int:
fmt.Printf("Integer multiplied by 2: %d\n", v*2)
case string:
fmt.Printf("String length: %d\n", len(v))
default:
fmt.Println("Unknown type")
}
// 2. Safe Comma-OK Type Assertion
if str, ok := val.(string); ok {
fmt.Println("Extracted String:", str)
}
}
func main() {
ProcessValue(42)
ProcessValue("Hello Go")
}3. Troubleshooting & Common Errors#
Error 1: Interface Contains Nil Pointer But Is Not Nil#
The Cause: An interface variable holding a nil pointer struct contains type info, so i == nil evaluates to false!
var p *EmailNotifier = nil
var n Notifier = p
// ⚠️ n is NOT nil because it holds type metadata (*EmailNotifier)!
if n != nil {
// n.Notify("test") 💥 Panics inside method if it dereferences nil pointer!
}Summary & Next Steps#
In this episode:
- We satisfied Go interfaces implicitly without
implements. - We wrote polymorphic functions accepting small interfaces.
- We used comma-ok Type Assertions and Type Switches.
In Episode 10: Idiomatic Error Handling, we will master explicit error returns, %w wrapping, errors.Is, and errors.As!

