Commit b95048f3 authored by Rob Pike's avatar Rob Pike

some stuff about interfaces. not enough yet.

R=rsc
DELTA=209  (129 added, 24 deleted, 56 changed)
OCL=35675
CL=35680
parent 400fa1c8
...@@ -85,7 +85,7 @@ type T struct { ...@@ -85,7 +85,7 @@ type T struct {
</pre> </pre>
<p> <p>
<code>gofmt</code> will make the columns line up: <code>gofmt</code> will make the columns line up.
</p> </p>
<pre> <pre>
...@@ -101,7 +101,7 @@ All code in the libraries has been formatted with <code>gofmt</code>. ...@@ -101,7 +101,7 @@ All code in the libraries has been formatted with <code>gofmt</code>.
<p> <p>
Some formatting details remain. Very briefly: Some formatting details remain. Very briefly,
</p> </p>
<dl> <dl>
...@@ -212,7 +212,7 @@ have a doc comment. ...@@ -212,7 +212,7 @@ have a doc comment.
Doc comments work best as complete English sentences, which allow Doc comments work best as complete English sentences, which allow
a wide variety of automated presentations. a wide variety of automated presentations.
The first sentence should be a one-sentence summary that The first sentence should be a one-sentence summary that
starts with the name being declared: starts with the name being declared.
</p> </p>
<pre> <pre>
...@@ -366,7 +366,7 @@ Semicolons are never required at the top level. ...@@ -366,7 +366,7 @@ Semicolons are never required at the top level.
Also they are separators, not terminators, so they Also they are separators, not terminators, so they
can be left off the last element of a statement or declaration list, can be left off the last element of a statement or declaration list,
a convenience a convenience
for one-line <code>funcs</code> and the like: for one-line <code>funcs</code> and the like.
</p> </p>
<pre> <pre>
...@@ -378,7 +378,7 @@ func CopyInBackground(dst, src chan Item) { ...@@ -378,7 +378,7 @@ func CopyInBackground(dst, src chan Item) {
<p> <p>
In fact, semicolons can be omitted at the end of any "StatementList" in the In fact, semicolons can be omitted at the end of any "StatementList" in the
grammar, which includes things like cases in <code>switch</code> grammar, which includes things like cases in <code>switch</code>
statements: statements.
</p> </p>
<pre> <pre>
...@@ -444,7 +444,7 @@ especially when the body contains a control statement such as a ...@@ -444,7 +444,7 @@ especially when the body contains a control statement such as a
<p> <p>
Since <code>if</code> and <code>switch</code> accept an initialization Since <code>if</code> and <code>switch</code> accept an initialization
statement, it's common to see one used to set up a local variable: statement, it's common to see one used to set up a local variable.
</p> </p>
<pre> <pre>
...@@ -474,7 +474,7 @@ This is a example of a common situation where code must analyze a ...@@ -474,7 +474,7 @@ This is a example of a common situation where code must analyze a
sequence of error possibilities. The code reads well if the sequence of error possibilities. The code reads well if the
successful flow of control runs down the page, eliminating error cases successful flow of control runs down the page, eliminating error cases
as they arise. Since error cases tend to end in <code>return</code> as they arise. Since error cases tend to end in <code>return</code>
statements, the resulting code needs no <code>else</code> statements: statements, the resulting code needs no <code>else</code> statements.
</p> </p>
<pre> <pre>
...@@ -493,10 +493,10 @@ codeUsing(f, d); ...@@ -493,10 +493,10 @@ codeUsing(f, d);
<h3 id="for">For</h3> <h3 id="for">For</h3>
<p> <p>
The Go <code>for</code> loop is similar to—but not the same as—C's. The Go <code>for</code> loop is similar to&mdash;but not the same as&mdash;C's.
It unifies <code>for</code> It unifies <code>for</code>
and <code>while</code> and there is no <code>do-while</code>. and <code>while</code> and there is no <code>do-while</code>.
There are three forms, only one of which has semicolons: There are three forms, only one of which has semicolons.
</p> </p>
<pre> <pre>
// Like a C for // Like a C for
...@@ -510,7 +510,7 @@ for { } ...@@ -510,7 +510,7 @@ for { }
</pre> </pre>
<p> <p>
Short declarations make it easy to declare the index variable right in the loop: Short declarations make it easy to declare the index variable right in the loop.
</p> </p>
<pre> <pre>
sum := 0; sum := 0;
...@@ -521,7 +521,7 @@ for i := 0; i < 10; i++ { ...@@ -521,7 +521,7 @@ for i := 0; i < 10; i++ {
<p> <p>
If you're looping over an array, slice, string, or map a <code>range</code> clause can set If you're looping over an array, slice, string, or map a <code>range</code> clause can set
it all up for you: it all up for you.
</p> </p>
<pre> <pre>
var m map[string] int; var m map[string] int;
...@@ -553,7 +553,7 @@ character 語 starts at byte position 6 ...@@ -553,7 +553,7 @@ character 語 starts at byte position 6
<p> <p>
Finally, since Go has no comma operator and <code>++</code> and <code>--</code> Finally, since Go has no comma operator and <code>++</code> and <code>--</code>
are statements not expressions, if you want to run multiple variables in a <code>for</code> are statements not expressions, if you want to run multiple variables in a <code>for</code>
you should use parallel assignment: you should use parallel assignment.
</p> </p>
<pre> <pre>
// Reverse a // Reverse a
...@@ -570,9 +570,9 @@ The expressions need not be constants or even integers, ...@@ -570,9 +570,9 @@ The expressions need not be constants or even integers,
the cases are evaluated top to bottom until a match is found, the cases are evaluated top to bottom until a match is found,
and if the <code>switch</code> has no expression it switches on and if the <code>switch</code> has no expression it switches on
<code>true</code>. <code>true</code>.
It's therefore possible—and idiomatic—to write an It's therefore possible&mdash;and idiomatic&mdash;to write an
<code>if</code>-<code>else</code>-<code>if</code>-<code>else</code> <code>if</code>-<code>else</code>-<code>if</code>-<code>else</code>
chain as a <code>switch</code>: chain as a <code>switch</code>.
</p> </p>
<pre> <pre>
...@@ -591,7 +591,7 @@ func unhex(c byte) byte { ...@@ -591,7 +591,7 @@ func unhex(c byte) byte {
<p> <p>
There is no automatic fall through, but cases can be presented There is no automatic fall through, but cases can be presented
in comma-separated lists: in comma-separated lists.
<pre> <pre>
func shouldEscape(c byte) bool { func shouldEscape(c byte) bool {
switch c { switch c {
...@@ -784,7 +784,7 @@ is defined to be an unlocked mutex. ...@@ -784,7 +784,7 @@ is defined to be an unlocked mutex.
</p> </p>
<p> <p>
The zero-value-is-useful property works transitively. Consider this type declaration: The zero-value-is-useful property works transitively. Consider this type declaration.
</p> </p>
<pre> <pre>
...@@ -797,7 +797,7 @@ type SyncedBuffer struct { ...@@ -797,7 +797,7 @@ type SyncedBuffer struct {
<p> <p>
Values of type <code>SyncedBuffer</code> are also ready to use immediately upon allocation Values of type <code>SyncedBuffer</code> are also ready to use immediately upon allocation
or just declaration. In this snippet, both <code>p</code> and <code>v</code> will work or just declaration. In this snippet, both <code>p</code> and <code>v</code> will work
correctly without further arrangement: correctly without further arrangement.
</p> </p>
<pre> <pre>
...@@ -810,7 +810,7 @@ var v SyncedBuffer; // type SyncedBuffer ...@@ -810,7 +810,7 @@ var v SyncedBuffer; // type SyncedBuffer
<p> <p>
Sometimes the zero value isn't good enough and an initializing Sometimes the zero value isn't good enough and an initializing
constructor is necessary, as in this example derived from constructor is necessary, as in this example derived from
package <code>os</code>: package <code>os</code>.
</p> </p>
<pre> <pre>
...@@ -852,7 +852,7 @@ the storage associated with the variable survives after the function ...@@ -852,7 +852,7 @@ the storage associated with the variable survives after the function
returns. returns.
In fact, taking the address of a composite literal In fact, taking the address of a composite literal
allocates a fresh instance each time it is evaluated, allocates a fresh instance each time it is evaluated,
so we can combine these last two lines: so we can combine these last two lines.
</p> </p>
<pre> <pre>
...@@ -872,7 +872,7 @@ order, with the missing ones left as their respective zero values. Thus we coul ...@@ -872,7 +872,7 @@ order, with the missing ones left as their respective zero values. Thus we coul
<p> <p>
As a limiting case, if a composite literal contains no fields at all, it creates As a limiting case, if a composite literal contains no fields at all, it creates
a zero value for the type. These two expressions are equivalent: a zero value for the type. These two expressions are equivalent.
</p> </p>
<pre> <pre>
...@@ -884,7 +884,7 @@ new(File) ...@@ -884,7 +884,7 @@ new(File)
Composite literals can also be created for arrays, slices, and maps, Composite literals can also be created for arrays, slices, and maps,
with the field labels being indices or map keys as appropriate. with the field labels being indices or map keys as appropriate.
In these examples, the initializations work regardless of the values of <code>EnoError</code>, In these examples, the initializations work regardless of the values of <code>EnoError</code>,
<code>Eio</code>, and <code>Einval</code>, as long as they are distinct: <code>Eio</code>, and <code>Einval</code>, as long as they are distinct.
</p> </p>
<pre> <pre>
...@@ -928,7 +928,7 @@ structure, that is, a pointer to a <code>nil</code> slice value. ...@@ -928,7 +928,7 @@ structure, that is, a pointer to a <code>nil</code> slice value.
<p> <p>
These examples illustrate the difference between <code>new()</code> and These examples illustrate the difference between <code>new()</code> and
<code>make()</code>: <code>make()</code>.
</p> </p>
<pre> <pre>
...@@ -959,7 +959,7 @@ To lay the foundation for that topic, here are a few words about arrays. ...@@ -959,7 +959,7 @@ To lay the foundation for that topic, here are a few words about arrays.
<p> <p>
There are major differences between the ways arrays work in Go and C. There are major differences between the ways arrays work in Go and C.
In Go: In Go,
</p> </p>
<ul> <ul>
<li> <li>
...@@ -976,7 +976,7 @@ and <code>[20]int</code> are distinct. ...@@ -976,7 +976,7 @@ and <code>[20]int</code> are distinct.
<p> <p>
The value property can be useful but also expensive; if you want C-like behavior and efficiency, The value property can be useful but also expensive; if you want C-like behavior and efficiency,
you can pass a pointer to the array: you can pass a pointer to the array.
</p> </p>
<pre> <pre>
...@@ -1021,14 +1021,14 @@ func (file *File) Read(buf []byte) (n int, err os.Error) ...@@ -1021,14 +1021,14 @@ func (file *File) Read(buf []byte) (n int, err os.Error)
<p> <p>
The method returns the number of bytes read and an error value, if The method returns the number of bytes read and an error value, if
any. To read into the first 32 bytes of a larger buffer any. To read into the first 32 bytes of a larger buffer
<code>b</code>, <i>slice</i> (here used as a verb) the buffer: <code>b</code>, <i>slice</i> (here used as a verb) the buffer.
</p> </p>
<pre> <pre>
n, err := f.Read(buf[0:32]); n, err := f.Read(buf[0:32]);
</pre> </pre>
<p> <p>
Such slicing is common and efficient. In fact, leaving efficiency aside for Such slicing is common and efficient. In fact, leaving efficiency aside for
the moment, this snippet would also read the first 32 bytes of the buffer: the moment, this snippet would also read the first 32 bytes of the buffer.
</p> </p>
<pre> <pre>
var n int; var n int;
...@@ -1044,7 +1044,7 @@ the moment, this snippet would also read the first 32 bytes of the buffer: ...@@ -1044,7 +1044,7 @@ the moment, this snippet would also read the first 32 bytes of the buffer:
</pre> </pre>
<p> <p>
The length of a slice may be changed as long as it still fits within The length of a slice may be changed as long as it still fits within
the limits of the underyling array; just assign it to a slice of the limits of the underlying array; just assign it to a slice of
itself. The <i>capacity</i> of a slice, accessible by the built-in itself. The <i>capacity</i> of a slice, accessible by the built-in
function <code>cap</code>, reports the maximum length the slice may function <code>cap</code>, reports the maximum length the slice may
assume. Here is a function to append data to a slice. If the data assume. Here is a function to append data to a slice. If the data
...@@ -1262,8 +1262,8 @@ map[string] int ...@@ -1262,8 +1262,8 @@ map[string] int
</pre> </pre>
<p> <p>
If you want to control the default format for a custom type, all that's required is to define If you want to control the default format for a custom type, all that's required is to define
a method <code>String() string</code> on the type. (Methods are the subject of the next a method <code>String() string</code> on the type.
section.) For our simple type <code>T</code>, that might look like this. For our simple type <code>T</code>, that might look like this.
</p> </p>
<pre> <pre>
func (t *T) String() string { func (t *T) String() string {
...@@ -1352,14 +1352,14 @@ func (p *ByteSlice) Write(data []byte) (n int, err os.Error) { ...@@ -1352,14 +1352,14 @@ func (p *ByteSlice) Write(data []byte) (n int, err os.Error) {
<p> <p>
then the type <code>*ByteSlice</code> satisfies the standard interface then the type <code>*ByteSlice</code> satisfies the standard interface
<code>io.Writer</code>, which is handy. For instance, we can <code>io.Writer</code>, which is handy. For instance, we can
print into one: print into one.
</p> </p>
<pre> <pre>
var b ByteSlice; var b ByteSlice;
fmt.Fprintf(&amp;b, "This hour has %d days\n", 7); fmt.Fprintf(&amp;b, "This hour has %d days\n", 7);
</pre> </pre>
<p> <p>
Notice that we must pass the address of a <code>ByteSlice</code> We pass the address of a <code>ByteSlice</code>
because only <code>*ByteSlice</code> satisfies <code>io.Writer</code>. because only <code>*ByteSlice</code> satisfies <code>io.Writer</code>.
The rule about pointers vs. values for receivers is that value methods The rule about pointers vs. values for receivers is that value methods
can be invoked on pointers and values, but pointer methods can only be can be invoked on pointers and values, but pointer methods can only be
...@@ -1372,38 +1372,167 @@ By the way, the idea of using <code>Write</code> on a slice of bytes ...@@ -1372,38 +1372,167 @@ 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>Interfaces</h2> <h2 id="interfaces_and_types">Interfaces and the interplay of types</h2>
<!--- <h3 id="interfaces">Interfaces</h3>
<h3 id="accept-interface-values">Accept interface values</h3> <p>
Interfaces in Go provide a way to specify the behavior of an
object: if something can do <em>this</em>, then it can be used
<em>here</em>. We've seen a couple of simple examples already;
custom printers can be implemented by a <code>String</code> method
while <code>Fprintf</code> can generate output to anything
with a <code>Write</code> method.
Interfaces with only one or two methods are common in Go, and are
usually given a name derived from the method, such as <code>io.Writer</code>
for something that implements <code>Write</code>.
</p>
<p>
A type can implement multiple interfaces.
For instance, a collection can be sorted
by the routines in package <code>sort</code> if it implements
<code>sort.Interface</code>, which contains <code>Len()</code>,
<code>Less(i, j int)</code>, and <code>Swap(i, j int)</code>,
and it could also have a custom formatter.
In this contrived example <code>Sequence</code> satisfies both.
</p>
<pre>
type Sequence []int
buffered i/o takes a Reader, not an os.File. XXX // Methods required by sort.Interface.
func (s Sequence) Len() int {
return len(s)
}
func (s Sequence) Less(i, j int) bool {
return s[i] < s[j]
}
func (s Sequence) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
<h3 id="return-interface-values">Return interface values</h3> // Method for printing - sorts the elements before printing.
func (s Sequence) String() string {
sort.Sort(s);
str := "[";
for i, elem := range s {
if i > 0 {
str += " "
}
str += fmt.Sprint(elem);
}
return str + "]";
}
</pre>
<h3 id="conversions">Conversions</h3>
<p> <p>
If a type exists only to implement an interface The <code>String</code> method of <code>Sequence</code> is recreating the
and has no exported methods beyond that interface, work that <code>Sprint</code> already does for slices. We can share the
there is no need to publish the type itself. effort if we convert the <code>Sequence</code> to a plain
Instead, write a constructor that returns an interface value. <code>[]int</code> before calling <code>Sprint</code>.
</p>
<pre>
func (s Sequence) String() string {
sort.Sort(s);
return fmt.Sprint([]int(s));
}
</pre>
<p>
The conversion causes <code>s</code> to be treated as an ordinary slice
and therefore receive the default formatting.
Without the conversion, <code>Sprint</code> would find the
<code>String</code> method of <code>Sequence</code> and recur indefinitely.
Because the two types (<code>Sequence</code> and <code>[]int</code>)
are the same if we ignore the type name, it's legal to convert between them.
The conversion doesn't create a new value, it just temporarily acts
as though the existing value has a new type.
(There are other legal conversions, such as from integer to float, that
do create a new value.)
</p> </p>
<p>
It's an idiom of Go code to convert the
type of an expression to access a different
set of methods. As an example, we could use the existing
type <code>sort.IntArray</code> to reduce the entire example
to this:
</p>
<pre>
type Sequence []int
// Method for printing - sorts the elements before printing
func (s Sequence) String() string {
sort.IntArray(s).Sort();
return fmt.Sprint([]int(s))
}
</pre>
<p> <p>
For example, both <code>crc32.NewIEEE()</code> and <code>adler32.New()</code> Now, instead of having <code>Sequence</code> implement multiple
return type <code>hash.Hash32</code>. interfaces (sorting and printing), we're using the ability of a data item to be
converted to multiple types (<code>Sequence</code>, <code>sort.IntArray</code>
and <code>[]int</code>), each of which does some part of the job.
That's more unusual in practice but can be effective.
</p>
<h3 id="generality">Generality</h3>
<p>
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.
It also avoids the need to repeat the documentation
on every instance of a common method.
</p>
<p>
In such cases, the constructor should return an interface value
rather than the implementing type.
As an example, in the hash libraries
both <code>crc32.NewIEEE()</code> and <code>adler32.New()</code>
return the interface type <code>hash.Hash32</code>.
Substituting the CRC-32 algorithm for Adler-32 in a Go program Substituting the CRC-32 algorithm for Adler-32 in a Go program
requires only changing the constructor call: requires only changing the constructor call;
the rest of the code is unaffected by the change of algorithm. the rest of the code is unaffected by the change of algorithm.
</p> </p>
<p>
A similar approach allows the streaming cipher algorithms
in the <code>crypto/block</code> package to be
separated from the block ciphers they chain together.
By analogy to the <code>bufio</code> package,
they wrap a <code>Cipher</code> interface
and they return <code>hash.Hash</code>,
<code>io.Reader</code>, or <code>io.Writer</code>
interface values, not direct implementations.
</p>
<p>
The interface to <code>crypto/block</code> includes:
</p>
<pre>
type Cipher interface {
BlockSize() int;
Encrypt(src, dst []byte);
Decrypt(src, dst []byte);
}
<h3 id="asdf">Use interface adapters to expand an implementation</h3> // NewECBDecrypter returns a reader that reads data
// from r and decrypts it using c in electronic codebook (ECB) mode.
XXX func NewECBDecrypter(c Cipher, r io.Reader) io.Reader
<h3 id="fdsa">Use anonymous fields to incorporate an implementation</h3>
XXX // NewCBCDecrypter returns a reader that reads data
---> // from r and decrypts it using c in cipher block chaining (CBC) mode
// with the initialization vector iv.
func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader
</pre>
<p>
<code>NewECBDecrypter</code> and <code>NewCBCReader</code> apply not
just to one specific encryption algorithm and data source but to any
implementation of the <code>Cipher</code> interface and any
<code>io.Reader</code>. Because they return <code>io.Reader</code>
interface values, replacing ECB
encryption with CBC encryption is a localized change. The constructor
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.
</p>
<h2 id="errors">Errors</h2> <h2 id="errors">Errors</h2>
...@@ -1490,30 +1619,6 @@ for try := 0; try < 2; try++ { ...@@ -1490,30 +1619,6 @@ for try := 0; try < 2; try++ {
header, body, checksum := buf[0:20], buf[20:n-4], buf[n-4:n]; header, body, checksum := buf[0:20], buf[20:n-4], buf[n-4:n];
</pre> </pre>
<h2 id="types">Programmer-defined types</h2>
<p>Packages that export only a single type can
shorten <code>NewTypeName</code> to <code>New</code>;
the vector constructor is
<code>vector.New</code>, not <code>vector.NewVector</code>.
</p>
<p>
A type that is intended to be allocated
as part of a larger struct may have an <code>Init</code> method
that must be called explicitly.
Conventionally, the <code>Init</code> method returns
the object being initialized, to make the constructor trivial:
</p>
<a href="xxx">go/src/pkg/container/vector/vector.go</a>:
<pre>
func New(len int) *Vector {
return new(Vector).Init(len)
}
</pre>
<h2>Data-Driven Programming</h2> <h2>Data-Driven Programming</h2>
<p> <p>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment