In ../src/io/io.go
, below interface has Write
method
type Writer interface {
Write(p []byte) (n int, err error)
}
In ../src/net/http/server.go
, below interface ResponseWriter
implements Write
method of Writer
interface
type ResponseWriter interface {
Header() Header
Write([]byte) (int, error)
WriteHeader(statusCode int)
}
From coding style aspect, Is Writer
interface embed in ResponseWriter
interface preferred over implementing it?
Remember that an interface itself implements nothing at all. It simply says, "if your package implements all these functions with exactly these signatures, then it can be used where an X interface is required".
Think of it as a contractual type: "If I say that a FooInterface
can be used here, then anything that does all the things I said a FooInterface
does is acceptable."
A Writer
by the definition here needs to implement Write
, somehow. What that particular method does is not important from the standpoint of the interface, only that it exists, and accepts a byte
array, returning an int
and an error
. What it does is up to the implementation of the package.
Maybe it it programs a drone to skywrite the bytes, maybe it hacks the Times Square billboards and prints the message there. All that matters is that, at a minimum, you can call Write
and get back the expected return values. The side effects are not defined by the interface, but by the implementation in the package.
The fact that a Write
function exists with the right signature makes the package conform to the Writer
interface. It could have a dozen other methods; it only matters that Write
is there to meet the requirement.
ResponseWriter
and Writer
are related only in that ResponseWriter
says "I happen to require that ResponseWriter
s implement the same interface as a Writer
- we both implement Write([]byte) (int, error)
; to be a ResponseWriter
, it's also necessary to implement Header
and WriteHeader
." If the Skywriting
package also implemented these two functions, then it would be a ResponseWriter
.
type ResponseWriter interface
does not define what Header
and WriteHeader
do, only that they must exist and have the right signature. The relationship to Writer
is only that we've agreed that conceptually a ResponseWriter
is a specialized Writer
. It would be perfectly possible to define an OddResponseWriter
interface that didn't include Write
(though it would be confusing).
More specialized names imply that the interface with the more specialized name is a superset of the one with the simpler name, but there is no enforcement of this by Go itself. We can, as @colminator notes, enforce this by embedding the simpler type; this lets the compiler enforce that the specialized interface also meets the less-specialized interface's contract, and ensures that the code will fail to compile if the embedded interface's requirements change but the embedder has not changed to meet it.
This implementation of interfaces gives us a lot of flexibility to substitute one package for another without rewrites. If a function says "please pass me a Writer
interface so I can write out my results", that code doesn't need to be touched if you swap in a new package with a different name, as long as what you pass in has a Writer
that matches up.
I think you're touching on embedding.
So in your example above, one could rewrite the interface definition like so:
type ResponseWriter interface {
Header() Header
io.Writer // embedded interface type
WriteHeader(statusCode int)
}
But this is a pre-arrangement with the io
package.
The http/server.go
interface definition is able to exist without knowledge of the io
package.
By http/server.go
's interface requiring a function Write
with an identical signature to io.Writer
allows lots of other benefits without establishing a formal link to the (external) io
package.