Reader/Writer are basic interfaces designed in Golang. For example, if a struct have a function like:
type Example struct {
}func (e *Example) Write(p byte[]) (n int, err error) {}func (e *Example) Read(p byte[]) (n int, err error) {}
We will say Example
implements Read/Write interface, and if we want do a force type conversions, we will see Example is type of Reader&Writer
reader, err := example.(Reader)
if err != nil {
// Shouldn't throw an error here.
}
But how Reader/Writer works ?
For example, File
struct already implement the Read/Write
function then call the syscall read/write function read the data from file.
func (f *File) Read(b []byte) (n int, err error) {
if err := f.checkValid("read"); err != nil {
return 0, err
}
n, e := f.read(b)
if n == 0 && len(b) > 0 && e == nil {
return 0, io.EOF
}
if e != nil {
err = &PathError{"read", f.name, e}
}
return n, err
}
And another example here is
type Example struct {
r File
}
func (e *Example) Read(p []byte)(n int, err error) {
return e.f.Read(p)
}
This is an example see how do we pass the Reader/Writer
from one struct to another, when example
instance initialized with a File
, example
can read the data what f
get and example
still be a type of Reader
.So we can build a Reader
chain like
type A struct {
b B
}
type B struct {
c C
}
func (a *A) call() (r Reader, err error) {
return a.b.c
}
// If A,B,C all implement Read function, then when we call
// a.call function will get an C instance which is type of Reader.
So how to design the API for Reader/Writer struct ?
If we want build a chain of Reader/Writer
and has a friendly API for others, how can we do ? In golang source code file we can see two type of API design for example:
func (a *A) call(in Writer) (out Writer, err error) {}
or
func (b *B) call(out Writer) (in Writer, err error) {}
First, there is no best practice for the API design, when you call the function you will be get two types of way,
// A
out, err := a.call(w)
io.Copy(w, reader)// B
in, err := a.call(w)
io.Copy(in, reader)
hmm, it seems the exampleA
is a very common way when we design the API, we apply parameter and then get the result. But has the pointer support just like C-lang, so we can have solution B
. But B
is used every where inside of golang, so when do we need use A
. In my opinion, when we want write some describe data or meta data for content data, we need use A
because inside of call
function Writer/w
is already initialized and we can access all the functions, props it has.
Conclusion
Reader/Writer
are very important in golang, understanding how it works is very important and a friendly API is also a important things.
All this is my personal thoughts.
Refs: