Useful Interfaces
Related interfaces:
- io.Writer
- encoding.TextUnmarshaler
io.Writer
io.Writer is the interface that wraps the basic Write() method that writes len(p) bytes from p to the underlying data stream.
type Writer interface {
Write(p []byte) (n int, err error)
}
A well-designed type, with Output functionality, can specify an io.Writer and call its Write() method somewhere when necessary.
Applications
A Logger in pkg log represents an active logging object that generates lines of output to an io.Writer. Each logging operation makes a single call to the Writer’s Write method. New creates a new Logger. The out variable sets the destination to which log data will be written.
func New(out io.Writer, prefix string, flag int) *Logger {...}
func (l *Logger) Output(calldepth int, s string) error {
...
_, err := l.out.Write(l.buf)
return err
}
Package flag implements command-line flag parsing.
It will print usage or error messages when the command line
comes across a -h flag or an invalid flag. The output destination
is the an object of io.Writer, with os.Stderr as a default.
func (f *FlagSet) PrintDefaults() {
...
fmt.Fprint(f.Output(), b.String(), "\n")
...
}
// Output returns the destination for usage and error messages.
// os.Stderr is returned if output was not set or was set to nil.
func (f *FlagSet) Output() io.Writer {
if f.output == nil {
return os.Stderr
}
return f.output
}
A bytes.Buffer is a variable-sized buffer of bytes that implements the io.Writer and io.Reader interfaces. It provides a convenient way of writing testcases of packages.
// in standard pkg bytes
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(len(p))
if !ok {
m = b.grow(len(p))
}
return copy(b.buf[m:], p), nil
}
// in standard pkg log
// the testcase uses bytes.Buffer to simulate a console log env
func TestOutput(t *testing.T) {
const testString = "test"
var b bytes.Buffer
l := New(&b, "", 0) // specify the output destination
l.Println(testString) // it will trigger l.out.Write()
if expect := testString + "\n"; b.String() != expect {
t.Errorf("log output should match %q is %q", expect, b.String())
}
}
Package net/http provides HTTP client and server implementations.
Handler is an interface to handle incoming request. Its first
argument is an object implementing ResponseWriter interface,
which is also an io.Writer.
// user code
// register a handler function
// (It will be converted to HandlerFunc somewhere when necessary)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
// w is also an io.Writer and
// w.Write() will be called inside fmt.Fprintf()
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
// src code in pkg net/http
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type ResponseWriter interface {
Header() Header
// it makes a http.ResponseWriter work as an io.Writer
Write([]byte) (int, error)
WriteHeader(statusCode int)
}
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
encoding.TextUnmarshaler
Package encoding defines interfaces shared by other packages that convert data to and from byte-level and textual representations. TextUnmarshaler is the interface implemented by an object that can unmarshal a textual representation of itself.
type TextUnmarshaler interface {
UnmarshalText(text []byte) error
}
A well-designed type, with Parse functionality, can specify an encoding.TextUnmarshaler and call its UnmarshalText() method somewhere when necessary.
Applications
Package flag implements command-line flag parsing. To parse a special flag, we can specify an encoding.TextUnmarshaler for it.
// in standard pkg flag
func (f *FlagSet) TextVar(p encoding.TextUnmarshaler, name string, value encoding.TextMarshaler, usage string)
func (v textValue) Set(s string) error {
return v.p.UnmarshalText([]byte(s))
}
// an example of parsing the net.Ip type that implement
// encoding.TextUnmarshaler
// TextVar binds the flag "ip" to the variable ip := net.IP
var ip net.IP
fs.TextVar(&ip, "ip", net.IPv4(192, 168, 0, 100), "`IP address` to parse")
// Parse will call flag.Value.Set(value) for each flag
fs.Parse([]string{"-ip", "127.0.0.1"})
fmt.Printf("{ip: %v}\n\n", ip)