Golang interface keyword
last modified May 7, 2025
This tutorial explains how to use the interface
keyword in Go.
We'll cover interface basics with practical examples of polymorphism.
The interface type defines a set of method signatures. Any type that implements these methods implicitly satisfies the interface.
In Go, interfaces enable polymorphism and flexible code design. They allow different types to be treated uniformly if they implement the same interface.
Basic interface definition
A simple interface defines method signatures without implementations. This example shows a basic interface and its implementation.
package main import "fmt" type Speaker interface { Speak() string } type Dog struct{} func (d Dog) Speak() string { return "Woof!" } type Cat struct{} func (c Cat) Speak() string { return "Meow!" } func main() { animals := []Speaker{Dog{}, Cat{}} for _, animal := range animals { fmt.Println(animal.Speak()) } }
The Speaker
interface requires a Speak
method. Both
Dog
and Cat
implement it, allowing polymorphic usage.
Empty interface
The empty interface interface{}
has no methods. All types implement
it, making it useful for generic functions.
package main import "fmt" func describe(i interface{}) { fmt.Printf("Type: %T, Value: %v\n", i, i) } func main() { describe(42) describe("hello") describe(3.14) describe([]int{1, 2, 3}) }
The describe
function accepts any type via the empty interface.
It prints the type and value of whatever is passed to it.
Interface composition
Interfaces can embed other interfaces to create more complex contracts. This example combines multiple interfaces.
package main import "fmt" type Walker interface { Walk() } type Runner interface { Run() } type Athlete interface { Walker Runner } type Human struct{} func (h Human) Walk() { fmt.Println("Human walking") } func (h Human) Run() { fmt.Println("Human running") } func main() { var athlete Athlete = Human{} athlete.Walk() athlete.Run() }
Athlete
combines Walker
and Runner
.
Human
implements both methods, satisfying the composite interface.
Type assertions
Type assertions check if an interface value holds a specific type. This example demonstrates safe type checking.
package main import "fmt" func checkType(i interface{}) { if s, ok := i.(string); ok { fmt.Printf("It's a string: %s\n", s) } else if n, ok := i.(int); ok { fmt.Printf("It's an int: %d\n", n) } else { fmt.Printf("Unknown type: %T\n", i) } } func main() { checkType("hello") checkType(42) checkType(3.14) }
The checkType
function uses type assertions to determine the
underlying type of the interface value and handle each case appropriately.
Type switches
Type switches simplify type assertions with multiple cases. This example shows a cleaner way to handle different types.
package main import "fmt" func process(i interface{}) { switch v := i.(type) { case int: fmt.Printf("Integer: %d\n", v) case string: fmt.Printf("String: %s\n", v) case bool: fmt.Printf("Boolean: %v\n", v) default: fmt.Printf("Unknown type: %T\n", v) } } func main() { process(42) process("gopher") process(true) process(3.14) }
The type switch syntax i.(type)
checks multiple possible types in
a clean, readable way. Each case handles a different type.
Practical example: Database abstraction
Interfaces are powerful for creating abstractions. This example shows a simple database interface with multiple implementations.
package main import "fmt" type Database interface { Connect() string Query(q string) string } type MySQL struct{} func (m MySQL) Connect() string { return "MySQL connected" } func (m MySQL) Query(q string) string { return fmt.Sprintf("MySQL query: %s", q) } type PostgreSQL struct{} func (p PostgreSQL) Connect() string { return "PostgreSQL connected" } func (p PostgreSQL) Query(q string) string { return fmt.Sprintf("PostgreSQL query: %s", q) } func main() { databases := []Database{MySQL{}, PostgreSQL{}} for _, db := range databases { fmt.Println(db.Connect()) fmt.Println(db.Query("SELECT * FROM users")) } }
The Database
interface defines common operations. Both database
types implement it, allowing uniform usage despite different implementations.
Interface satisfaction verification
Go can verify at compile time if a type satisfies an interface. This example shows explicit interface satisfaction checking.
package main import "fmt" type Writer interface { Write([]byte) (int, error) } type ConsoleWriter struct{} func (cw ConsoleWriter) Write(data []byte) (int, error) { n, err := fmt.Println(string(data)) return n, err } func main() { var w Writer = ConsoleWriter{} w.Write([]byte("Hello, interfaces!")) // Compile-time check var _ Writer = (*ConsoleWriter)(nil) }
The line var _ Writer = (*ConsoleWriter)(nil)
verifies that
ConsoleWriter
satisfies Writer
at compile time.
This is a common Go idiom.
Source
This tutorial covered the interface
keyword in Go with practical
examples of polymorphism, type assertions, and interface composition.
Author
List all Golang tutorials.