A processing function need not know whether its input comes from a file, standard input, or a memory buffer. The Go standard-library package io defines small interfaces for the operations it needs: Reader for reading, Writer for writing, and Closer for closing. A type can be used through an interface when it has the required methods. section 10.3 section 2.8.2
Reader requires a Read method that accepts a byte slice and returns a byte count and an error. An os.File opened with os.Open has that method, so it can be passed where an io.Reader is expected. These interfaces establish conventions; they do not read or write anything by themselves. section 2.8.2
Listing 2.40 Excerpt from go doc io.Reader
type Reader interface {
Read(p []byte) (n int, err error)
}
Reader is the interface that wraps the basic Read method.
Read reads up to len(p) bytes into p. It returns the number of bytes
read (0 <= n <= len(p)) and any error encountered. Even if Read returns
n < len(p), it may use all of p as scratch space during the call. If
some data is available but not len(p) bytes, Read conventionally returns
what is available instead of waiting for more.
The Reader declaration shows the complete method contract that an input type must satisfy. section 2.8.2
Keep processing independent of its destination
A function can accept an io.Reader and an io.Writer rather than a particular file type: func process(w io.Writer, r io.Reader) error { data, err := io.ReadAll(r) if err != nil { return err } _, err = fmt.Fprintf(w, "%s", data) return err } The caller can supply file or standard-input sources and direct output to a file or the screen. fmt.Fprintf writes to the supplied Writer rather than always writing to standard output. section 10.3
Interfaces can also be combined: ReadCloser and WriteCloser add closing behavior to reading or writing. For other stream arrangements, io.MultiReader combines readers for sequential input, while io.MultiWriter sends output to multiple destinations. section 10.3
