mirror of
https://github.com/golang/go
synced 2024-11-25 02:07:58 -07:00
interfaces and methods.
R=rsc DELTA=160 (143 added, 5 deleted, 12 changed) OCL=35748 CL=35758
This commit is contained in:
parent
b83549a7e6
commit
2119b3672d
@ -310,11 +310,12 @@ which is a clear, concise name.
|
|||||||
Moreover,
|
Moreover,
|
||||||
because imported entities are always addressed with their package name, <code>bufio.Reader</code>
|
because imported entities are always addressed with their package name, <code>bufio.Reader</code>
|
||||||
does not conflict with <code>io.Reader</code>.
|
does not conflict with <code>io.Reader</code>.
|
||||||
Similarly, the constructor for <code>vector.Vector</code>
|
Similarly, the function to make new instances of <code>vector.Vector</code>
|
||||||
would normally be called <code>NewVector</code> but since
|
—which is the definition of a <em>constructor</em> in Go—would
|
||||||
|
normally be called <code>NewVector</code> but since
|
||||||
<code>Vector</code> is the only type exported by the package, and since the
|
<code>Vector</code> is the only type exported by the package, and since the
|
||||||
package is called <code>vector</code>, it's called just <code>New</code>,
|
package is called <code>vector</code>, it's called just <code>New</code>.
|
||||||
which clients of the package see as <code>vector.New</code>.
|
Clients of the package see that as <code>vector.New</code>.
|
||||||
Use the package structure to help you choose good names.
|
Use the package structure to help you choose good names.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -1372,7 +1373,7 @@ By the way, the idea of using <code>Write</code> on a slice of bytes
|
|||||||
is implemented by <code>bytes.Buffer</code>.
|
is implemented by <code>bytes.Buffer</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="interfaces_and_types">Interfaces and the interplay of types</h2>
|
<h2 id="interfaces_and_types">Interfaces and other types</h2>
|
||||||
|
|
||||||
<h3 id="interfaces">Interfaces</h3>
|
<h3 id="interfaces">Interfaces</h3>
|
||||||
<p>
|
<p>
|
||||||
@ -1382,7 +1383,7 @@ object: if something can do <em>this</em>, then it can be used
|
|||||||
custom printers can be implemented by a <code>String</code> method
|
custom printers can be implemented by a <code>String</code> method
|
||||||
while <code>Fprintf</code> can generate output to anything
|
while <code>Fprintf</code> can generate output to anything
|
||||||
with a <code>Write</code> method.
|
with a <code>Write</code> 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 <code>io.Writer</code>
|
usually given a name derived from the method, such as <code>io.Writer</code>
|
||||||
for something that implements <code>Write</code>.
|
for something that implements <code>Write</code>.
|
||||||
</p>
|
</p>
|
||||||
@ -1477,10 +1478,11 @@ That's more unusual in practice but can be effective.
|
|||||||
<p>
|
<p>
|
||||||
If a type exists only to implement an interface
|
If a type exists only to implement an interface
|
||||||
and has no exported methods beyond that interface,
|
and has no exported methods beyond that interface,
|
||||||
there is no need to publish the type itself.
|
there is no need to export the type itself.
|
||||||
Publishing just the interface makes it easy for
|
Exporting just the interface makes it clear that
|
||||||
other implementations with different properties
|
it's the behavior that matters, not the implementation,
|
||||||
to mirror the job of the original type.
|
and that other implementations with different properties
|
||||||
|
can mirror the behavior of the original type.
|
||||||
It also avoids the need to repeat the documentation
|
It also avoids the need to repeat the documentation
|
||||||
on every instance of a common method.
|
on every instance of a common method.
|
||||||
</p>
|
</p>
|
||||||
@ -1502,7 +1504,7 @@ By analogy to the <code>bufio</code> package,
|
|||||||
they wrap a <code>Cipher</code> interface
|
they wrap a <code>Cipher</code> interface
|
||||||
and they return <code>hash.Hash</code>,
|
and they return <code>hash.Hash</code>,
|
||||||
<code>io.Reader</code>, or <code>io.Writer</code>
|
<code>io.Reader</code>, or <code>io.Writer</code>
|
||||||
interface values, not direct implementations.
|
interface values, not specific implementations.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The interface to <code>crypto/block</code> includes:
|
The interface to <code>crypto/block</code> includes:
|
||||||
@ -1534,6 +1536,147 @@ calls must be edited, but because the code must treat the result only
|
|||||||
as an <code>io.Reader</code>, it won't notice the difference.
|
as an <code>io.Reader</code>, it won't notice the difference.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3 id="interface_methods">Interfaces and methods</h3>
|
||||||
|
<p>
|
||||||
|
Since almost anything can have methods attached, almost anything can
|
||||||
|
satisfy an interface. One illustrative example is in the <code>http</code>
|
||||||
|
package, which defines the <code>Handler</code> interface. Any object
|
||||||
|
that implements <code>Handler</code> can serve HTTP requests.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
type Handler interface {
|
||||||
|
ServeHTTP(*Conn, *Request);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
(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.
|
||||||
|
<pre>
|
||||||
|
import "http"
|
||||||
|
...
|
||||||
|
ctr := new(Counter);
|
||||||
|
http.Handle("/counter", ctr);
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
But why make <code>Counter</code> a struct? An integer is all that's needed.
|
||||||
|
(The receiver needs to be a pointer so the increment is visible to the caller.)
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
// Simpler counter server.
|
||||||
|
type Counter int
|
||||||
|
|
||||||
|
func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
|
||||||
|
ctr++;
|
||||||
|
fmt.Fprintf(c, "counter = %d\n", ctr);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Finally, let's say we wanted to present on <code>/args</code> the arguments
|
||||||
|
used when invoking the server binary.
|
||||||
|
It's easy to write a function to print the arguments:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
func ArgServer() {
|
||||||
|
for i, s := range os.Args {
|
||||||
|
fmt.Println(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
Since we can write a method for (almost) any type, we can write a method
|
||||||
|
for a function.
|
||||||
|
The <code>http</code> package contains this code:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
<code>HandlerFunc</code> is a type with a method, <code>ServeHTTP</code>,
|
||||||
|
so values of that type can serve HTTP requests. Look at the implementation
|
||||||
|
of the method: the receiver is a function, <code>f</code>, and the method
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To make <code>ArgServer</code> into an HTTP server, we first give it the right
|
||||||
|
signature.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
// Argument server.
|
||||||
|
func ArgServer(c *http.Conn, req *http.Request) {
|
||||||
|
for i, s := range os.Args {
|
||||||
|
fmt.Fprintln(c, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
<code>ArgServer</code> has same signature as <code>HandlerFunc</code>,
|
||||||
|
so the function can be converted to that type to access its methods,
|
||||||
|
just as we converted <code>Sequence</code> to <code>[]int</code> earlier.
|
||||||
|
The code to set it up is short:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
http.Handle("/args", http.HandlerFunc(ArgServer));
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
When someone visits the page <code>/args</code>,
|
||||||
|
the handler installed at that page has type
|
||||||
|
<code>HandlerFunc</code> and value <code>ArgServer</code>.
|
||||||
|
The HTTP server will invoke the method <code>ServeHTTP</code>
|
||||||
|
of that type, with that receiver, which will in turn call
|
||||||
|
<code>ArgServer</code> (via the invocation <code>f(c, req)</code>
|
||||||
|
inside <code>HandlerFunc.ServeHTTP</code>) and the arguments
|
||||||
|
will be displayed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 id="errors">Errors</h2>
|
<h2 id="errors">Errors</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -1604,8 +1747,6 @@ for try := 0; try < 2; try++ {
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h2>Testing</h2>
|
|
||||||
|
|
||||||
<h2>More to come</h2>
|
<h2>More to come</h2>
|
||||||
|
|
||||||
<!---
|
<!---
|
||||||
@ -1696,10 +1837,7 @@ used by both <code>TestEncoder</code> and <code>TestDecoder</code>.
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
This data-driven style dominates in the Go package tests.
|
This data-driven style dominates in the Go package tests.
|
||||||
<!--
|
<font color="red">((link to go code search for 'for.*range' here))</font>
|
||||||
<br>
|
|
||||||
link to go code search for 'for.*range' here
|
|
||||||
-->
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 id="reflect.DeepEqual">Use reflect.DeepEqual to compare complex values</h3>
|
<h3 id="reflect.DeepEqual">Use reflect.DeepEqual to compare complex values</h3>
|
||||||
|
Loading…
Reference in New Issue
Block a user