~/Go Interfaces Deep Dive

Jul 15, 2021


Go interfaces are a central feature for achieving abstraction, polymorphism, and decoupling in Go codebases. Interfaces provide a way to specify the behavior of objects without exposing implementation details.

Interface Syntax and Declaration

In Go, an interface is declared using the type keyword. An interface specifies a method set. Any type that implements these methods implicitly satisfies the interface.

1
2
3
type Reader interface {
    Read(p []byte) (n int, err error)
}

Documentation

Interface Satisfaction

Go uses structural typing. A type satisfies an interface by implementing its method set, with no explicit declaration.

1
2
3
4
5
6
7
8
type MyReader struct{}

func (MyReader) Read(p []byte) (n int, err error) {
    // Implementation
    return 0, nil
}

var r Reader = MyReader{}

Implicit interfaces

Dynamic Types and Values

An interface{} value contains a pair: a concrete value and a concrete type. This enables dynamic dispatch at runtime.

Type assertions are used to extract values:

1
2
3
if r, ok := i.(MyReader); ok {
    // Use r as MyReader
}

Empty Interface

The interface{} type has zero methods and can hold any value. It is used in APIs such as fmt.Print and encoding/json.

Interface Composition

Interfaces can embed other interfaces to compose behaviors.

1
2
3
4
type ReadWriter interface {
    Reader
    Writer
}

Combining interfaces is common in Go standard io package.

Interface Values and Nil

An interface value is nil if both the type and value are nil. Care is required when returning interface values from functions, especially with nil underlying types. See the FAQ on interface nil.

Common Usage Patterns

Best Practices

Code Example: Interface-based API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
type Shape interface {
    Area() float64
}

type Square struct {
    Side float64
}

func (s Square) Area() float64 {
    return s.Side * s.Side
}

func PrintArea(sh Shape) {
    fmt.Println(sh.Area())
}

Package example

Interface Reflection

Reflection with reflect.TypeOf and reflect.ValueOf enables introspection of arbitrary interfaces.

Conclusion

Go interfaces provide a powerful tool for abstraction, testability, and decoupling. They are used pervasively in standard libraries and in large codebases. Understanding their mechanics is critical for advanced Go development.

Tags: [golang]