Interfaces in Go define behavior - they specify what a type can do, not how it does it. An interface is a collection of method signatures. Any type that implements all the methods in an interface automatically satisfies that interface.Unlike other languages, Go uses implicit implementation - you don’t need to explicitly declare that a type implements an interface.
type printer interface { print()}type book struct { title string price money}// book implements printer because it has a print() methodfunc (b book) print() { fmt.Printf("%-15s: %s\n", b.title, b.price.string())}type game struct { title string price money}// game implements printer toofunc (g *game) print() { fmt.Printf("%-15s: %s\n", g.title, g.price.string())}
There’s no implements keyword in Go. A type implements an interface simply by implementing all of its methods.
Interfaces enable you to write functions that work with any type that implements the required behavior:
type list []*game // Can only hold gamesfunc (l list) print() { for _, it := range l { it.print() }}func main() { var store list store = append(store, &minecraft, &tetris) store.print() // Can't add books or other types!}
var p printerp = book{title: "Go Programming", price: 29.99}// p now holds: (value: book{...}, type: book)p = &game{title: "Chess", price: 9.99}// p now holds: (value: *game{...}, type: *game)
Type assertions let you access the concrete value inside an interface:
var p printer = book{title: "Go", price: 29.99}// Type assertionb := p.(book)fmt.Println(b.title) // "Go"// This would panic if p doesn't hold a book!// g := p.(game) // panic: interface holds book, not game
Always use the two-value form value, ok := i.(Type) unless you’re absolutely certain of the type, to avoid panics.
The receiver type matters for interface satisfaction:
Pointer vs Value
type Printer interface { Print()}type Document struct { content string}// Pointer receiverfunc (d *Document) Print() { fmt.Println(d.content)}func Display(p Printer) { p.Print()}func main() { d := Document{content: "Hello"} // Display(d) // ✗ Error: Document doesn't implement Printer Display(&d) // ✓ Works: *Document implements Printer // However, this works due to auto-addressing: d.Print() // ✓ Works: Go converts to (&d).Print()}
Rule: If an interface method has a pointer receiver, only pointers to that type satisfy the interface.If an interface method has a value receiver, both values and pointers satisfy the interface.
type BasicPrinter interface { Print()}type ColorPrinter interface { BasicPrinter PrintColor(color string)}func display(p BasicPrinter) { p.Print() // Check if p also supports color if cp, ok := p.(ColorPrinter); ok { cp.PrintColor("red") }}