CodeNebula
Go🚀Advancedadvanced

Interface Composition

Go · Advanced · Run with go run

Explanation

Go interfaces can embed other interfaces, building larger contracts from smaller ones. The standard library uses this heavily: `io.ReadWriter` embeds both `io.Reader` and `io.Writer`; `io.ReadWriteCloser` adds `io.Closer`. This compositional approach lets you accept exactly the capabilities you need — nothing more, nothing less.

Real-World Scenario

A compression library accepts `io.ReadWriter` — it needs both read and write on the same stream. A network conn (`net.Conn`) satisfies this; so does a `bytes.Buffer`. No inheritance hierarchy required.

Quick Snippet

snippet.go
type Reader interface { Read([]byte) (int, error) }
type Writer interface { Write([]byte) (int, error) }
type Closer interface { Close() error }

// Composed interfaces
type ReadWriter interface {
    Reader
    Writer
}
type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

// Accept minimum required capability
func compress(rw io.ReadWriter) error {
    // reads uncompressed, writes compressed to the same conn
}

// Custom composed interface for a specific domain
type Repository interface {
    Querier
    Mutator
    io.Closer
}

Full Example

interface_composition.go
// Compile: go run interface_composition.go
// Output:
//   wrote 5 bytes
//   read back: hello
//   closed
package main

import (
	"bytes"
	"fmt"
	"io"
)

// Small interfaces compose into larger contracts
type Reader interface{ Read([]byte) (int, error) }
type Writer interface{ Write([]byte) (int, error) }
type Closer interface{ Close() error }

type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

// buffer satisfies ReadWriteCloser
type buffer struct {
	bytes.Buffer
}

func (b *buffer) Close() error {
	fmt.Println("closed")
	return nil
}

func useStream(rwc ReadWriteCloser) {
	n, _ := rwc.Write([]byte("hello"))
	fmt.Println("wrote", n, "bytes")

	data, _ := io.ReadAll(rwc)
	fmt.Println("read back:", string(data))

	rwc.Close()
}

func main() {
	useStream(&buffer{})
}
Run command
go run interface_composition.go