Interfaces
Go interfaces are satisfied implicitly. If a type has the methods an interface requires, it implements that interface - no implements keyword needed. This decouples packages and enables powerful composition.
Implicit Satisfaction
type Speaker interface {
Speak() string
}
type Dog struct{ Name string }
func (d Dog) Speak() string {
return d.Name + " says woof!"
}
// Dog implements Speaker without declaring it.
// This compiles because Dog has a Speak() string method.
var s Speaker = Dog{Name: "Rex"}
fmt.Println(s.Speak()) // "Rex says woof!"
The compiler verifies satisfaction at the assignment point. If Dog is missing the Speak method, you get a compile error.
Small Interfaces
Go’s best interfaces are small, often just one method. The stdlib is full of them:
| Interface | Method | What it means |
|---|---|---|
io.Reader | Read(p []byte) (n int, err error) | Can read bytes |
io.Writer | Write(p []byte) (n int, err error) | Can write bytes |
fmt.Stringer | String() string | Has string representation |
error | Error() string | Is an error |
sort.Interface | Len, Less, Swap | Can be sorted |
http.Handler | ServeHTTP(w, r) | Handles HTTP requests |
// Anything with a Read method works with io.Copy, json.Decoder, etc.
type MyReader struct{ data []byte; pos int }
func (r *MyReader) Read(p []byte) (int, error) {
if r.pos >= len(r.data) {
return 0, io.EOF
}
n := copy(p, r.data[r.pos:])
r.pos += n
return n, nil
}
Tip: “The bigger the interface, the weaker the abstraction.” - Rob Pike. Keep interfaces to 1-3 methods.
Embedding for Composition
Combine small interfaces into larger ones:
type ReadWriter interface {
io.Reader
io.Writer
}
type ReadWriteCloser interface {
io.Reader
io.Writer
io.Closer
}
Struct embedding works similarly:
type Logger struct {
io.Writer // embeds Writer - Logger gains Write method
prefix string
}
func (l Logger) Log(msg string) {
fmt.Fprintf(l, "[%s] %s\n", l.prefix, msg)
}
logger := Logger{Writer: os.Stdout, prefix: "APP"}
logger.Log("starting up")
Accept Interfaces, Return Structs
This is Go’s most important interface guideline:
// Good: accepts interface - works with any Reader
func CountLines(r io.Reader) (int, error) {
scanner := bufio.NewScanner(r)
count := 0
for scanner.Scan() {
count++
}
return count, scanner.Err()
}
// Works with files, HTTP responses, strings, buffers...
CountLines(os.Stdin)
CountLines(resp.Body)
CountLines(strings.NewReader("line1\nline2"))
Why return structs? Concrete types are easier to construct, document, and extend without breaking changes. Define interfaces at the call site, not the implementation.
// Define the interface where you USE it, not where you implement it
package myservice
type Store interface {
Get(ctx context.Context, id string) (Item, error)
Put(ctx context.Context, item Item) error
}
type Service struct {
store Store
}
func New(store Store) *Service {
return &Service{store: store}
}
The any Type and Type Assertions
any is an alias for interface{} (the empty interface). Any value satisfies it.
func printType(v any) {
switch val := v.(type) {
case string:
fmt.Println("string:", val)
case int:
fmt.Println("int:", val)
case []byte:
fmt.Println("bytes:", len(val))
default:
fmt.Printf("unknown: %T\n", val)
}
}
Type assertions extract the concrete value:
var i any = "hello"
s := i.(string) // panics if i is not a string
s, ok := i.(string) // safe - ok is false if wrong type
if ok {
fmt.Println(s)
}
Gotcha: Prefer generics over
anyfor type-safe containers. Useanyfor truly heterogeneous data (JSON parsing, plugin systems).
Interface Compliance Check
Verify at compile time that a type satisfies an interface:
// Compile-time check: *Dog must implement Speaker
var _ Speaker = (*Dog)(nil)
This costs nothing at runtime and catches missing methods early.
Nil Interface Pitfall
An interface value is nil only when both its type and value are nil:
var p *Dog = nil
var s Speaker = p
fmt.Println(s == nil) // false! s has type *Dog, value nil
fmt.Println(p == nil) // true
This is the single most common interface gotcha in Go. See Gotchas for details.
Next: Error Handling | Concurrency