Skip to content

Interfaces

Go interfaces are satisfied implicitly — there’s no implements keyword. If a type has the right methods, it satisfies the interface, full stop.

type Stringer interface {
String() string
}
type Point struct{ X, Y int }
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.X, p.Y)
}

Point now satisfies Stringer without ever mentioning it. This decouples the interface’s definition from its implementations — you can define an interface for types you don’t own.

The standard library’s most-used interfaces are tiny:

type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}

io.Reader and io.Writer are one method each, yet files, network connections, byte buffers, and compressors all implement them — letting you write code like io.Copy(dst, src) that works with any combination.

interface{} (or any, its alias since Go 1.18) is satisfied by every type — useful for genuinely dynamic data, though generics (covered later) now handle most cases that used to need it.

var v any = "hello"
s, ok := v.(string) // type assertion
if ok {
fmt.Println(s)
}
switch x := v.(type) {
case string:
fmt.Println("string:", x)
case int:
fmt.Println("int:", x)
default:
fmt.Println("unknown type")
}