1
0
mirror of https://github.com/golang/go synced 2024-11-22 06:04:39 -07:00

embedding part 1.

R=rsc
DELTA=128  (104 added, 0 deleted, 24 changed)
OCL=35835
CL=35839
This commit is contained in:
Rob Pike 2009-10-16 11:13:40 -07:00
parent d5337e9829
commit 8840726edc

View File

@ -1,6 +1,6 @@
<!-- Effective Go --> <!-- Effective Go -->
<!-- interfaces; cast,conversion, type assertion; embedding; errors; testing; initialization --> <!-- testing?; concurrency; initialization-->
<h2 id="introduction">Introduction</h2> <h2 id="introduction">Introduction</h2>
@ -34,7 +34,7 @@ should read first.
<h3 id="read">Examples</h3> <h3 id="read">Examples</h3>
<p> <p>
The <a href="http://s2/?dir=//depot2/go/src/pkg">Go package sources</a> The <a href="/src/pkg/">Go package sources</a>
are intended to serve not are intended to serve not
only as the core library but also as examples of how to only as the core library but also as examples of how to
use the language. use the language.
@ -1551,7 +1551,7 @@ type Handler interface {
<p> <p>
For brevity, let's ignore POSTs and assume HTTP requests are always For brevity, let's ignore POSTs and assume HTTP requests are always
GETs; that simplification does not affect the way the handlers are GETs; that simplification does not affect the way the handlers are
made. Here's a trivial but complete implementation of a handler to set up. Here's a trivial but complete implementation of a handler to
count the number of times the count the number of times the
page is visited. page is visited.
</p> </p>
@ -1568,7 +1568,7 @@ func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
</pre> </pre>
<p> <p>
(Keeping with our theme, note how <code>Fprintf</code> can print to an HTTP connection.) (Keeping with our theme, note how <code>Fprintf</code> can print to an HTTP connection.)
For reference, here's how to set up such a server. For reference, here's how to attach such a server to a node on the URL tree.
<pre> <pre>
import "http" import "http"
... ...
@ -1595,17 +1595,17 @@ has been visited? Tie a channel to the web page.
<pre> <pre>
// A channel that sends a notification on each visit. // A channel that sends a notification on each visit.
// (Probably want the channel to be buffered.) // (Probably want the channel to be buffered.)
type Chan chan int type Chan chan *http.Request
func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) { func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
ch <- 1; ch <- req;
fmt.Fprint(c, "notification sent"); fmt.Fprint(c, "notification sent");
} }
</pre> </pre>
<p> <p>
Finally, let's say we wanted to present on <code>/args</code> the arguments Finally, let's say we wanted to present on <code>/args</code> the arguments
used when invoking the server binary. used when invoking the server binary.
It's easy to write a function to print the arguments: It's easy to write a function to print the arguments.
</p> </p>
<pre> <pre>
func ArgServer() { func ArgServer() {
@ -1617,8 +1617,8 @@ func ArgServer() {
<p> <p>
How do we turn that into an HTTP server? We could make <code>ArgServer</code> How do we turn that into an HTTP server? We could make <code>ArgServer</code>
a method of some type whose value we ignore, but there's a cleaner way. a method of some type whose value we ignore, but there's a cleaner way.
Since we can write a method for (almost) any type, we can write a method Since we can define a method for any type except pointers and interfaces,
for a function. we can write a method for a function.
The <code>http</code> package contains this code: The <code>http</code> package contains this code:
</p> </p>
<pre> <pre>
@ -1641,8 +1641,8 @@ calls <code>f</code>. That may seem odd but it's no different from, say,
the receiver being a channel and the method sending on the channel. the receiver being a channel and the method sending on the channel.
</p> </p>
<p> <p>
To make <code>ArgServer</code> into an HTTP server, we first give it the right To make <code>ArgServer</code> into an HTTP server, we first modify it
signature. to have the right signature.
</p> </p>
<pre> <pre>
// Argument server. // Argument server.
@ -1653,30 +1653,134 @@ func ArgServer(c *http.Conn, req *http.Request) {
} }
</pre> </pre>
<p> <p>
<code>ArgServer</code> has same signature as <code>HandlerFunc</code>, <code>ArgServer</code> now has same signature as <code>HandlerFunc</code>,
so the function can be converted to that type to access its methods, so it can be converted to that type to access its methods,
just as we converted <code>Sequence</code> to <code>[]int</code> earlier. just as we converted <code>Sequence</code> to <code>IntArray</code>
The code to set it up is short: to access <code>IntArray.Sort</code>.
The code to set it up is concise:
</p> </p>
<pre> <pre>
http.Handle("/args", http.HandlerFunc(ArgServer)); http.Handle("/args", http.HandlerFunc(ArgServer));
</pre> </pre>
<p> <p>
When someone visits the page <code>/args</code>, When someone visits the page <code>/args</code>,
the handler installed at that page has type the handler installed at that page has value <code>ArgServer</code>
<code>HandlerFunc</code> and value <code>ArgServer</code>. and type <code>HandlerFunc</code>.
The HTTP server will invoke the method <code>ServeHTTP</code> The HTTP server will invoke the method <code>ServeHTTP</code>
of that type, with that receiver, which will in turn call of that type, with <code>ArgServer</code> as the receiver, which will in turn call
<code>ArgServer</code> (via the invocation <code>f(c, req)</code> <code>ArgServer</code> (via the invocation <code>f(c, req)</code>
inside <code>HandlerFunc.ServeHTTP</code>) and the arguments inside <code>HandlerFunc.ServeHTTP</code>).
will be displayed. The arguments will then be displayed.
</p> </p>
<p> <p>
In summary, we have made an HTTP server from a struct, an integer, In this section we have made an HTTP server from a struct, an integer,
a channel, and a function, all because interfaces are just sets of a channel, and a function, all because interfaces are just sets of
methods, which can be defined for (almost) any type. methods, which can be defined for (almost) any type.
</p> </p>
<h2 id="embedding">Embedding</h2>
<p>
Go does not provide the typical, type-driven notion of subclassing,
but it does have the ability to &ldquo;borrow&rdquo; pieces of an
implementation by <em>embedding</em> types within a struct or
interface.
</p>
<p>
Interface embedding is very simple.
We've mentioned the <code>io.Reader</code> and <code>io.Writer</code> interfaces before;
here are their definitions.
</p>
<pre>
type Reader interface {
Read(p []byte) (n int, err os.Error);
}
type Writer interface {
Write(p []byte) (n int, err os.Error);
}
</pre>
<p>
The <code>io</code> package also exports several other interfaces
that specify objects that can implement several such methods.
For instance, there is <code>io.ReadWriter</code>, an interface
containing both <code>Read</code> and <code>Write</code>.
We could specify <code>io.ReadWriter</code> by listing the
two methods explicitly, but it's easier and more evocative
to embed the two interfaces to form the new one, like this:
</p>
<pre>
// ReadWrite is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
Reader;
Writer;
}
</pre>
<p>
This says just what it looks like: A <code>ReadWriter</code> can do
what a <code>Reader</code> does <em>and</em> what a <code>Writer</code>
does; it is a union of the embedded interfaces (which must be disjoint
sets of methods).
Only interfaces can be embedded within interfaces.
<p>
The same basic idea applies to structs, but with more far-reaching
implications. The <code>bufio</code> package has two struct types,
<code>bufio.Reader</code> and <code>bufio.Writer</code>, each of
which of course implements the analogous interfaces from package
<code>io</code>.
And <code>bufio</code> also implements a buffered reader/writer,
which it does by combining a reader and a writer into one struct
using embedding: it lists the types within the struct
but does not give them field names.
</p>
<pre>
// ReadWriter stores pointers to a Reader and a Writer.
// It implements io.ReadWriter.
type ReadWriter struct {
*Reader;
*Writer;
}
</pre>
<p>
This struct could be written as
</p>
<pre>
type ReadWriter struct {
reader *Reader;
writer *Writer;
}
</pre>
<p>
but then to promote the methods of the fields and to
satisfy the <code>io</code> interfaces, we would also need
to provide forwarding methods, like this:
</p>
<pre>
func (rw *ReadWriter) Read(p []byte) (n int, err os.Error) {
return rw.reader.Read(p)
}
</pre>
<p>
By embedding the structs directly, we avoid this bookkeeping.
The methods of embedded types come along for free, which means that <code>bufio.ReadWriter</code>
not only has the methods of <code>bufio.Reader</code> and <code>bufio.Writer</code>,
it also satisfies all three interfaces:
<code>io.Reader</code>,
<code>io.Writer</code>, and
<code>io.ReadWriter</code>.
</p>
<p>
There's one important way in which embedding differs from subclassing. When we embed a type,
the methods of that type become methods of the out type
<but when they are invoked the receiver of the method is the inner type, not the outer one.
In our example, when the <code>Read</code> method of a <code>bufio.ReadWriter</code> is
invoked, it has the exactly the same effect as the forwarding method written out above;
the receiver is the <code>reader</code> field of the <code>ReadWriter</code>, not the
<code>ReadWriter</code> itself.
</p>
<h2 id="errors">Errors</h2> <h2 id="errors">Errors</h2>
<p> <p>
@ -1735,7 +1839,7 @@ field for recoverable failures.
<pre> <pre>
for try := 0; try < 2; try++ { for try := 0; try < 2; try++ {
file, err := os.Open(filename, os.O_RDONLY, 0); file, err = os.Open(filename, os.O_RDONLY, 0);
if err == nil { if err == nil {
return return
} }