Skip to content

Go Interfaces

An interface is a collection of method signatures. It defines a "contract"—any type that provides those methods is said to "implement" the interface.

Defining an Interface

package main

import "fmt"

// geometry interface defines the methods any shape must have
type geometry interface {
    area() float64
}

type rect struct {
    width, height float64
}

// rect implements geometry because it has an area() method
func (r rect) area() float64 {
    return r.width * r.height
}

func measure(g geometry) {
    fmt.Println("Area:", g.area())
}

func main() {
    r := rect{width: 3, height: 4}
    measure(r)
}

Why use Interfaces?

  • Polymorphism: You can write a single function (like measure) that works with many different types, as long as they follow the contract.
  • Decoupling: Your code doesn't need to know the exact type of object it's working with, only what it can do.
  • Mocking/Testing: You can swap real implementations (like a database) with "mock" versions for testing.

The Empty Interface (any or interface{})

An interface with zero methods is satisfied by every type. In modern Go, we often use the keyword any.

1
2
3
func printAnything(i any) {
    fmt.Println(i)
}

Type Assertions

If you have an interface value and need to get the original type back, use a type assertion:

1
2
3
4
5
6
var i any = "hello"

s, ok := i.(string)
if ok {
    fmt.Println(s) // "hello"
}

Important Notes

  • Implicit Implementation: You don't need to say implements geometry. If your type has the right methods, it just works.
  • Small Interfaces: In Go, smaller interfaces (1 or 2 methods) are usually better than large ones.