> Is there a list of best practices on how to effectively use buffers vs.
> readers/writers?
It's really up to what you want to do. Buffering the IO when syscalls
are involved (network, files, pipes) is not a bad way to go though,
but sometimes it's nice to have the obvious semantics without any
buffering. (Do note that some libraries add a buffer for you, like
net/http.)
> When should I use bytes.NewReader instead of bufio.NewReader?
These do two fundamentally different things; bytes.NewReader creates a
Reader from a byte slice (that is, a chunk of memory you already have
in your program.) Useful if you want to pass a byte slice to some
other API that expects a Reader. bufio.NewReader on the other hand is
for wrapping existing Readers (usually ones whose Read method is
relatively expensive, like a TCP connection or a file) to coalesce a
bunch of easy-to-program small Read calls into a few larger ones.
> Is the only benefit of using a bytes.Buffer to be able to treat the
> underlying slice dynamically?
I'm not sure what you mean by this. The main help that a bytes.Buffer
gives you over a []byte is that it implements a bunch of methods, so
you can use it to pass a []byte to other libraries expecting a Reader,
or use it to construct a []byte with a library expecting a Writer.
> Why would I want to use a bytes.Reader instead of a bytes.Buffer?
A bytes.Buffer is a buffer with two ends; you can only read from the
start of it, and you can only write to the end of it. No seeking.
There's no need to use both sides though; I often use it to construct
a chunk of encoded stuff in memory (by passing it to serialization
libraries expecting a Writer) then pull out the []byte at the end
(with (*bytes.Buffer).Bytes()), then stop using the bytes.Buffer and
pass the []byte I got to another layer for more work.
A bytes.Reader is more explicitly only for turning a []byte into
something that's a Reader; since no modifications are possible, it can
also implement Seek and ReadAt without ambiguity, thus being more
useful to pass to other functions expecting a ReaderAt or a ReadSeeker
or whatever.
In general I use bytes.Buffer for writing to byte slices, and
bytes.Reader for reading from byte slices.
-Chris K