Designing with Interfaces
Overview
Go interfaces enable polymorphism through implicit satisfaction—types implement interfaces by having matching methods, without explicit declarations.
Interface Basics
type Reader interface {
Read(p []byte) (n int, err error)
}
// Any type with Read method satisfies Reader
type File struct { /* ... */ }
func (f *File) Read(p []byte) (int, error) { /* ... */ }
type Buffer struct { /* ... */ }
func (b *Buffer) Read(p []byte) (int, error) { /* ... */ }Implicit Satisfaction
type Stringer interface {
String() string
}
type Person struct {
Name string
}
// Person implicitly implements Stringer
func (p Person) String() string {
return p.Name
}
var s Stringer = Person{Name: "Alice"} // Works!The Empty Interface
interface{} // Matches any type
any // Alias (Go 1.18+)
func print(v any) {
fmt.Println(v)
}
print(42)
print("hello")
print(true)Interface Values
An interface value holds a (type, value) pair:
var r io.Reader
r = os.Stdin // (type: *os.File, value: stdin)
r = &bytes.Buffer{} // (type: *bytes.Buffer, value: buf)nil Interface vs nil Value
var r io.Reader // nil interface (no type, no value)
var f *os.File // nil pointer
r = f // Interface holds (*os.File, nil)
r == nil // false! Has type, value is nilCommon Patterns
Accept Interface, Return Concrete
// Accept interface
func Process(r io.Reader) error { }
// Return concrete type
func NewBuffer() *bytes.Buffer {
return &bytes.Buffer{}
}Small Interfaces
type Reader interface {
Read([]byte) (int, error)
}
type Writer interface {
Write([]byte) (int, error)
}
type ReadWriter interface {
Reader
Writer
}Assert Interface Compliance
var _ io.Reader = (*MyReader)(nil) // Compile-time checkSummary
| Concept | Description |
|---|---|
| Implicit | No implements keyword |
any/interface{} |
Matches all types |
| Small interfaces | Prefer 1-3 methods |
| Accept interface | Flexible function parameters |