Standard library patterns · 3 MIN READ
Two interfaces, one method each
Write a function that works on a file, a string and a test buffer.
io.Reader has Read. io.Writer has Write. Files, network connections, HTTP bodies, gzip streams, strings.Reader and bytes.Buffer all satisfy one or both.
Accepting them instead of a concrete type is what makes Go code testable without mocks: the test passes a bytes.Buffer and reads the result back.
SEE THE IDEA
Separate the operation from the transport
- 01
Source
goio.ReaderProduces bytes
- 02
Transformation
gocopy or transformWorks against the small contracts
- 03
Destination
goio.WriterAccepts bytes
The same operation can use files, memory buffers or other implementations.
In practice
Accept interfaces that describe only the I/O behavior the function uses. A reader may return bytes and an error in the same call; process those bytes before the error. Standard helpers such as io.Copy and io.ReadAll handle the protocol details, but ReadAll uses memory proportional to the input.
Watch out
Do not assume one Read fills the requested buffer. For an exact byte count, use io.ReadFull.
Work through the exercise
package main
import (
"os"
"strings"
)
// WriteUpper copies src to dst, upper-cased. It should work with any
// reader and writer, not just files.
func WriteUpper(dst *os.File, src *strings.Reader) error {
return nil
}
func main() {}Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.
Progress stays in this browser. No account needed.