From 2119b3672db42e596e468a2516cf2e61729e683b Mon Sep 17 00:00:00 2001
From: Rob Pike bufio.Reader
does not conflict with io.Reader.
-Similarly, the constructor for vector.Vector
-would normally be called NewVector but since
+Similarly, the function to make new instances of vector.Vector
+—which is the definition of a constructor in Go—would
+normally be called NewVector but since
Vector is the only type exported by the package, and since the
-package is called vector, it's called just New,
-which clients of the package see as vector.New.
+package is called vector, it's called just New.
+Clients of the package see that as vector.New.
Use the package structure to help you choose good names.
Write on a slice of bytes
is implemented by bytes.Buffer.
-
@@ -1382,7 +1383,7 @@ object: if something can do this, then it can be used
custom printers can be implemented by a String method
while Fprintf can generate output to anything
with a Write method.
-Interfaces with only one or two methods are common in Go, and are
+Interfaces with only one or two methods are common in Go code, and are
usually given a name derived from the method, such as io.Writer
for something that implements Write.
If a type exists only to implement an interface and has no exported methods beyond that interface, -there is no need to publish the type itself. -Publishing just the interface makes it easy for -other implementations with different properties -to mirror the job of the original type. +there is no need to export the type itself. +Exporting just the interface makes it clear that +it's the behavior that matters, not the implementation, +and that other implementations with different properties +can mirror the behavior of the original type. It also avoids the need to repeat the documentation on every instance of a common method.
@@ -1502,7 +1504,7 @@ By analogy to thebufio package,
they wrap a Cipher interface
and they return hash.Hash,
io.Reader, or io.Writer
-interface values, not direct implementations.
+interface values, not specific implementations.
The interface to crypto/block includes:
@@ -1534,6 +1536,147 @@ calls must be edited, but because the code must treat the result only
as an io.Reader, it won't notice the difference.
+Since almost anything can have methods attached, almost anything can
+satisfy an interface. One illustrative example is in the http
+package, which defines the Handler interface. Any object
+that implements Handler can serve HTTP requests.
+
+type Handler interface {
+ ServeHTTP(*Conn, *Request);
+}
+
++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 +count the number of times the +page is visited. +
+
+// Simple counter server.
+type Counter struct {
+ n int;
+}
+
+func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
+ ctr.n++;
+ fmt.Fprintf(c, "counter = %d\n", ctr.n);
+}
+
+
+(Keeping with our theme, note how Fprintf can print to an HTTP connection.)
+For reference, here's how to set up such a server.
+
+import "http"
+...
+ctr := new(Counter);
+http.Handle("/counter", ctr);
+
+
+But why make Counter a struct? An integer is all that's needed.
+(The receiver needs to be a pointer so the increment is visible to the caller.)
+
+// Simpler counter server.
+type Counter int
+
+func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
+ ctr++;
+ fmt.Fprintf(c, "counter = %d\n", ctr);
+}
+
++What if your program has some internal state that needs to be notified that a page +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
+
+func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
+ ch <- 1;
+ fmt.Fprint(c, "notification sent");
+}
+
+
+Finally, let's say we wanted to present on /args the arguments
+used when invoking the server binary.
+It's easy to write a function to print the arguments:
+
+func ArgServer() {
+ for i, s := range os.Args {
+ fmt.Println(s);
+ }
+}
+
+
+How do we turn that into an HTTP server? We could make 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.
+The http package contains this code:
+
+// The HandlerFunc type is an adapter to allow the use of
+// ordinary functions as HTTP handlers. If f is a function
+// with the appropriate signature, HandlerFunc(f) is a
+// Handler object that calls f.
+type HandlerFunc func(*Conn, *Request)
+
+// ServeHTTP calls f(c, req).
+func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
+ f(c, req);
+}
+
+
+HandlerFunc is a type with a method, ServeHTTP,
+so values of that type can serve HTTP requests. Look at the implementation
+of the method: the receiver is a function, f, and the method
+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.
+
+// Argument server.
+func ArgServer(c *http.Conn, req *http.Request) {
+ for i, s := range os.Args {
+ fmt.Fprintln(c, s);
+ }
+}
+
+
+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:
+
+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 HTTP server will invoke the method ServeHTTP
+of that type, with that receiver, which will in turn call
+ArgServer (via the invocation f(c, req)
+inside HandlerFunc.ServeHTTP) and the arguments
+will be displayed.
+
+In summary, 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. +
+@@ -1604,8 +1747,6 @@ for try := 0; try < 2; try++ { } -