From 8840726edc7297e27c2ddfb3aa4e459b81a06859 Mon Sep 17 00:00:00 2001
From: Rob Pike
-The Go package sources
+The Go package sources
are intended to serve not
only as the core library but also as examples of how to
use the language.
@@ -1551,7 +1551,7 @@ type Handler interface {
For brevity, let's ignore POSTs and assume HTTP requests are always
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
page is visited.
(Keeping with our theme, note how
Finally, let's say we wanted to present on
How do we turn that into an HTTP server? We could make Introduction
@@ -34,7 +34,7 @@ should read first.
Examples
Fprintf
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.
import "http"
...
@@ -1595,17 +1595,17 @@ has been visited? Tie a channel to the web page.
// A channel that sends a notification on each visit.
// (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) {
- ch <- 1;
+ ch <- req;
fmt.Fprint(c, "notification sent");
}
/args
the arguments
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.
func ArgServer() {
@@ -1617,8 +1617,8 @@ func ArgServer() {
ArgServer
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
-for a function.
+Since we can define a method for any type except pointers and interfaces,
+we can write a method for a function.
The http
package contains this code:
@@ -1641,8 +1641,8 @@ calls
f
. That may seem odd but it's no different from, say,
the receiver being a channel and the method sending on the channel.
-To make ArgServer
into an HTTP server, we first give it the right
-signature.
+To make ArgServer
into an HTTP server, we first modify it
+to have the right signature.
// Argument server. @@ -1653,30 +1653,134 @@ func ArgServer(c *http.Conn, req *http.Request) { }
-ArgServer
has same signature as HandlerFunc
,
-so the function can be converted to that type to access its methods,
-just as we converted Sequence
to []int
earlier.
-The code to set it up is short:
+ArgServer
now has same signature as HandlerFunc
,
+so it can be converted to that type to access its methods,
+just as we converted Sequence
to IntArray
+to access IntArray.Sort
.
+The code to set it up is concise:
http.Handle("/args", http.HandlerFunc(ArgServer));
When someone visits the page /args
,
-the handler installed at that page has type
-HandlerFunc
and value ArgServer
.
+the handler installed at that page has value ArgServer
+and type HandlerFunc
.
The HTTP server will invoke the method ServeHTTP
-of that type, with that receiver, which will in turn call
+of that type, with ArgServer
as the receiver, which will in turn call
ArgServer
(via the invocation f(c, req)
-inside HandlerFunc.ServeHTTP
) and the arguments
-will be displayed.
+inside HandlerFunc.ServeHTTP
).
+The arguments will then be displayed.
-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 methods, which can be defined for (almost) any type.
++Go does not provide the typical, type-driven notion of subclassing, +but it does have the ability to “borrow” pieces of an +implementation by embedding types within a struct or +interface. +
+
+Interface embedding is very simple.
+We've mentioned the io.Reader
and io.Writer
interfaces before;
+here are their definitions.
+
+type Reader interface { + Read(p []byte) (n int, err os.Error); +} + +type Writer interface { + Write(p []byte) (n int, err os.Error); +} ++
+The io
package also exports several other interfaces
+that specify objects that can implement several such methods.
+For instance, there is io.ReadWriter
, an interface
+containing both Read
and Write
.
+We could specify io.ReadWriter
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:
+
+// ReadWrite is the interface that groups the basic Read and Write methods. +type ReadWriter interface { + Reader; + Writer; +} ++
+This says just what it looks like: A ReadWriter
can do
+what a Reader
does and what a Writer
+does; it is a union of the embedded interfaces (which must be disjoint
+sets of methods).
+Only interfaces can be embedded within interfaces.
+
+The same basic idea applies to structs, but with more far-reaching
+implications. The bufio
package has two struct types,
+bufio.Reader
and bufio.Writer
, each of
+which of course implements the analogous interfaces from package
+io
.
+And bufio
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.
+
+// ReadWriter stores pointers to a Reader and a Writer. +// It implements io.ReadWriter. +type ReadWriter struct { + *Reader; + *Writer; +} ++
+This struct could be written as +
++type ReadWriter struct { + reader *Reader; + writer *Writer; +} ++
+but then to promote the methods of the fields and to
+satisfy the io
interfaces, we would also need
+to provide forwarding methods, like this:
+
+func (rw *ReadWriter) Read(p []byte) (n int, err os.Error) { + return rw.reader.Read(p) +} ++
+By embedding the structs directly, we avoid this bookkeeping.
+The methods of embedded types come along for free, which means that bufio.ReadWriter
+not only has the methods of bufio.Reader
and bufio.Writer
,
+it also satisfies all three interfaces:
+io.Reader
,
+io.Writer
, and
+io.ReadWriter
.
+
+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
+bufio.ReadWriter
is
+invoked, it has the exactly the same effect as the forwarding method written out above;
+the receiver is the reader
field of the ReadWriter
, not the
+ReadWriter
itself.
+
@@ -1735,7 +1839,7 @@ field for recoverable failures.
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 { return } -- 2.50.0