Nobody signs a contract
In Java or C#, a class must declare implements Shape. In Go, nobody declares anything. If a type has the methods an interface asks for, it satisfies the interface — automatically, even if the interface was written years later in someone else's package. Donovan and Kernighan call this Go's most distinctive feature: interfaces describe behaviour, and types fit them by accident or by design.
That's why one function can print a temperature, an error, a file or your own types: fmt.Println only asks, "do you have a String() method?" Today you'll use interfaces, look inside them with type assertions, and meet the strangest bug in Go: a nil that isn't nil.
Satisfied without saying so
An interface type is a set of method signatures. A value of any type that has those methods can be stored in a variable of the interface type — implicit satisfaction. Calling a method on the interface runs the method of whatever concrete type is inside (dynamic dispatch).
package main
import "fmt"
type Speaker interface {
Speak() string
}
type Dog struct{}
type Robot struct{ Model string }
func (Dog) Speak() string { return "Bhau bhau!" }
func (r Robot) Speak() string { return r.Model + " says beep" }
func main() {
for _, s := range []Speaker{Dog{}, Robot{"R2"}} {
fmt.Println(s.Speak())
}
}- Method sets matter: if Speak has a pointer receiver, only *Dog satisfies Speaker, and var s Speaker = Dog{} fails to compile with "method Speak has pointer receiver".
- fmt.Stringer is interface { String() string }; error is interface { Error() string }.
- any (an alias for interface{}) is satisfied by every type — useful, but it says nothing about the value (mistake #8).
- Keep interfaces small and define them where they're used, not next to the implementation (mistakes #5–#7): "accept interfaces, return structs".