🎓 A1Learner
🔍
0 of 28 lessons completed

Go IO Interfaces

IO interfaces are small contracts for reading and writing streams of bytes. The io.Writer interface asks for one Write method, and io.Reader asks for one Read method.

Writing through an interface

A bytes.Buffer has a Write method, so a pointer to it fits in an io.Writer variable. Fprintf sends text through the variable, and the buffer holds the result.

package main

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

func main() {
	var buf bytes.Buffer
	var w io.Writer = &buf
	fmt.Fprintf(w, "Hello, %s", "writer")
	fmt.Println(buf.String())
}

A writer that counts

The counter type gives itself a Write method. The method adds the length of each slice to a stored count.

package main

import "fmt"

type counter struct {
	n int
}

func (c *counter) Write(p []byte) (int, error) {
	c.n += len(p)
	return len(p), nil
}

func main() {
	c := &counter{}
	n, _ := fmt.Fprintf(c, "count these bytes")
	fmt.Println("written:", n)
	fmt.Println("counted:", c.n)
}

Reading in chunks

A strings.Reader hands out its text a few bytes at a time. Each Read call fills the slice and reports how many bytes it placed.

package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	var r io.Reader = strings.NewReader("abcdefgh")
	buf := make([]byte, 3)
	n, _ := r.Read(buf)
	fmt.Println(n, string(buf[:n]))
	n, _ = r.Read(buf)
	fmt.Println(n, string(buf[:n]))
}

Example

package main

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

func shout(r io.Reader, w io.Writer) {
	data, _ := io.ReadAll(r)
	fmt.Fprint(w, strings.ToUpper(string(data)))
}

func main() {
	var out bytes.Buffer
	shout(strings.NewReader("go is fun"), &out)
	fmt.Println(out.String())
}

Key points

  • An io.Writer value is any value with a Write method that takes bytes in.
  • An io.Reader value is any value with a Read method that fills a byte slice.
  • A function that takes an io.Writer can write to any type that has a Write method.
  • fmt.Fprintf writes formatted text to any io.Writer.
  • Read returns the number of bytes it placed in the slice.

In this example, shout takes an io.Reader and an io.Writer. It reads all the text from the reader. It turns the text into upper case with strings.ToUpper. It writes the result to the writer, and main prints what the buffer holds.

Note

A type serves as a writer or a reader by having the right method, with no extra declaration.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Go Playground

Exercise

What makes a type usable as an io.Writer?