Interfaces
An interface in Go is a collection of method signatures. A value implements an interface by implementing its methods. There is no explicit declaration of intent.
Key Points
- Interfaces specify method signatures
- Implementation is implicit
- Empty interface accepts any value
- Enables polymorphism
- Small interfaces preferred
- Use assertions for underlying values
Defining and Implementing Interfaces
Define an interface by listing method signatures:
package main
import (
"fmt"
"math"
)
// Define an interface
type Shape interface {
Area() float64
}
// Rectangle implements Shape
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Circle implements Shape
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func PrintArea(s Shape) {
fmt.Println("Area:", s.Area())
}
func main() {
rect := Rectangle{Width: 10, Height: 5}
circ := Circle{Radius: 7}
PrintArea(rect)
PrintArea(circ)
}Area: 50
Area: 153.93804002589985The Empty Interface
The empty interface specifies zero methods and can hold values of any kind:
package main
import "fmt"
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}(<nil>, <nil>)
(42, int)
(hello, string)Type Assertions
A type assertion provides access to an underlying concrete value:
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
}hello
hello true
0 falseCommon Standard Interfaces
| Interface | Methods | Purpose |
|---|---|---|
fmt.Stringer | String() string | Custom string representation |
error | Error() string | Error handling |
io.Reader | Read([]byte) (int, error) | Read data from source |
io.Writer | Write([]byte) (int, error) | Write data to destination |
io.Closer | Close() error | Release resources |
Best Practices
| Practice | Guideline | Reason |
|---|---|---|
| Small contracts | Prefer 1-3 methods | Easier to implement |
| Accept contracts | Parameters should be contracts | More flexible |
| Output structs | Output concrete values | Clearer API |
| Define at use site | Consumer defines contracts | Minimal dependencies |