Interfaces allow programmers to decouple software by adhering to the dependency inversion principle. At a high level, an interface defines a method contract on structs:
package main
import (
"fmt"
"strings"
)
type pet interface {
Sound(int) string
NumLegs() int
}
type dog struct {}
func (d dog) Sound(length int) string {
return strings.Repeat("woof ", length)
}
func (d dog) NumLegs() int {
return 4
}
func Output(p pet) {
fmt.Printf("He walks on %d legs and makes the sound %s", p.NumLegs(), p.Sound(2))
}
func main() {
d := dog{}
Output(d)
}
Output
can be called on d
because dog
implements all the methods in the pet
interface.
Unlike java, go interfaces are implemented implicitly: there is no need to tell the compiler that we want dog
to adhere to the pet
interface.
Create a package that defines an interface and functions on the interface, and in main create structs that adhere to the interface. Run the package functions on the structs.
- "The bigger the interface, the weaker the abstraction" - Rob Pike.
- The empty interface (
interface{}
) means that any data type could be the argument.
Similar to the further reading in Structs 3.2, Interfaces also support composition. The io package has a lot of great examples:
go doc io Reader
go doc io Writer
go doc io ReadWriter