I am reading the source code for Go's io package and I came across a snippet I don't fully understand. Here it is
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}
where
type stringWriter interface {
WriteString(s string) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
The type assertion w.(stringWriter)
asserts that the dynamic type of w (i.e. Writer) implements the stringWriter interface. I don't see how this is possible given the type definitions of stringWriter and Writer. Assuming that this code is correct, what is it that I am missing?
You can easily build a type which implements Writer
as well as stringWriter
:
type StringWriter struct{}
func (s StringWriter) Write(in []byte) (int, error) {
return 0, nil
}
func (s StringWriter) WriteString(s string) (int, error) {
return s.Write([]byte(s))
}
So passing an instance of StringWriter
to io.WriteString
results in StringWriter.WriteString
being called.
The logic behind io.WriteString
is: Use WriteString
on the writer if it has such a method or fall back to string
to []byte
conversion otherwise. To test whether the instance implements a method or not, interfaces are used, as these are just method sets and can be tested for easily.