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++ { } -