From b95048f38d2cd757de3bd762c8570aa43f4c17a3 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 13 Oct 2009 14:32:21 -0700 Subject: [PATCH] some stuff about interfaces. not enough yet. R=rsc DELTA=209 (129 added, 24 deleted, 56 changed) OCL=35675 CL=35680 --- doc/effective_go.html | 249 ++++++++++++++++++++++++++++++------------ 1 file changed, 177 insertions(+), 72 deletions(-) diff --git a/doc/effective_go.html b/doc/effective_go.html index 73b91ca80f5..11f6eac51fa 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -85,7 +85,7 @@ type T struct {

-gofmt will make the columns line up: +gofmt will make the columns line up.

@@ -101,7 +101,7 @@ All code in the libraries has been formatted with gofmt.
 
 
 

-Some formatting details remain. Very briefly: +Some formatting details remain. Very briefly,

@@ -212,7 +212,7 @@ have a doc comment. Doc comments work best as complete English sentences, which allow a wide variety of automated presentations. The first sentence should be a one-sentence summary that -starts with the name being declared: +starts with the name being declared.

@@ -366,7 +366,7 @@ Semicolons are never required at the top level.
 Also they are separators, not terminators, so they
 can be left off the last element of a statement or declaration list,
 a convenience
-for one-line funcs and the like:
+for one-line funcs and the like.
 

@@ -378,7 +378,7 @@ func CopyInBackground(dst, src chan Item) {
 

In fact, semicolons can be omitted at the end of any "StatementList" in the grammar, which includes things like cases in switch -statements: +statements.

@@ -444,7 +444,7 @@ especially when the body contains a control statement such as a
 
 

Since if and switch 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.

@@ -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
 successful flow of control runs down the page, eliminating error cases
 as they arise.  Since error cases tend to end in return
-statements, the resulting code needs no else statements:
+statements, the resulting code needs no else statements.
 

@@ -493,10 +493,10 @@ codeUsing(f, d);
 

For

-The Go for loop is similar to—but not the same as—C's. +The Go for loop is similar to—but not the same as—C's. It unifies for and while and there is no do-while. -There are three forms, only one of which has semicolons: +There are three forms, only one of which has semicolons.

 // Like a C for
@@ -510,7 +510,7 @@ for { }
 

-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.

 sum := 0;
@@ -521,7 +521,7 @@ for i := 0; i < 10; i++ {
 
 

If you're looping over an array, slice, string, or map a range clause can set -it all up for you: +it all up for you.

 var m map[string] int;
@@ -553,7 +553,7 @@ character 語 starts at byte position 6
 

Finally, since Go has no comma operator and ++ and -- are statements not expressions, if you want to run multiple variables in a for -you should use parallel assignment: +you should use parallel assignment.

 // Reverse a
@@ -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,
 and if the switch has no expression it switches on
 true.
-It's therefore possible—and idiomatic—to write an
+It's therefore possible—and idiomatic—to write an
 if-else-if-else
-chain as a switch:
+chain as a switch.
 

@@ -591,7 +591,7 @@ func unhex(c byte) byte {
 
 

There is no automatic fall through, but cases can be presented -in comma-separated lists: +in comma-separated lists.

 func shouldEscape(c byte) bool {
     switch c {
@@ -784,7 +784,7 @@ is defined to be an unlocked mutex.
 

-The zero-value-is-useful property works transitively. Consider this type declaration: +The zero-value-is-useful property works transitively. Consider this type declaration.

@@ -797,7 +797,7 @@ type SyncedBuffer struct {
 

Values of type SyncedBuffer are also ready to use immediately upon allocation or just declaration. In this snippet, both p and v will work -correctly without further arrangement: +correctly without further arrangement.

@@ -810,7 +810,7 @@ var v SyncedBuffer;      // type  SyncedBuffer
 

Sometimes the zero value isn't good enough and an initializing constructor is necessary, as in this example derived from -package os: +package os.

@@ -852,7 +852,7 @@ the storage associated with the variable survives after the function
 returns.
 In fact, taking the address of a composite literal
 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.
 

@@ -872,7 +872,7 @@ order, with the missing ones left as their respective zero values.  Thus we coul
 
 

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.

@@ -884,7 +884,7 @@ new(File)
 Composite literals can also be created for arrays, slices, and maps,
 with the field labels being indices or map keys as appropriate.
 In these examples, the initializations work regardless of the values of EnoError,
-Eio, and Einval, as long as they are distinct:
+Eio, and Einval, as long as they are distinct.
 

@@ -928,7 +928,7 @@ structure, that is, a pointer to a nil slice value.
 
 

These examples illustrate the difference between new() and -make(): +make().

@@ -959,7 +959,7 @@ To lay the foundation for that topic, here are a few words about arrays.
 
 

There are major differences between the ways arrays work in Go and C. -In Go: +In Go,

  • @@ -976,7 +976,7 @@ and [20]int are distinct.

    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.

    @@ -1021,14 +1021,14 @@ func (file *File) Read(buf []byte) (n int, err os.Error)
     

    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 -b, slice (here used as a verb) the buffer: +b, slice (here used as a verb) the buffer.

     	n, err := f.Read(buf[0:32]);
     

    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.

     	var n int;
    @@ -1044,7 +1044,7 @@ the moment, this snippet would also read the first 32 bytes of the buffer:
     

    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 capacity of a slice, accessible by the built-in function cap, reports the maximum length the slice may assume. Here is a function to append data to a slice. If the data @@ -1262,8 +1262,8 @@ map[string] int

    If you want to control the default format for a custom type, all that's required is to define -a method String() string on the type. (Methods are the subject of the next -section.) For our simple type T, that might look like this. +a method String() string on the type. +For our simple type T, that might look like this.

     func (t *T) String() string {
    @@ -1352,14 +1352,14 @@ func (p *ByteSlice) Write(data []byte) (n int, err os.Error) {
     

    then the type *ByteSlice satisfies the standard interface io.Writer, which is handy. For instance, we can -print into one: +print into one.

     	var b ByteSlice;
     	fmt.Fprintf(&b, "This hour has %d days\n", 7);
     

    -Notice that we must pass the address of a ByteSlice +We pass the address of a ByteSlice because only *ByteSlice satisfies io.Writer. 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 @@ -1372,38 +1372,167 @@ By the way, the idea of using Write on a slice of bytes is implemented by bytes.Buffer.

    -

    Interfaces

    +

    Interfaces and the interplay of types

    - +// 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 +
    +

    +NewECBDecrypter and NewCBCReader apply not +just to one specific encryption algorithm and data source but to any +implementation of the Cipher interface and any +io.Reader. Because they return io.Reader +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 io.Reader, it won't notice the difference. +

    Errors

    @@ -1490,30 +1619,6 @@ for try := 0; try < 2; try++ { header, body, checksum := buf[0:20], buf[20:n-4], buf[n-4:n];
-

Programmer-defined types

- -

Packages that export only a single type can -shorten NewTypeName to New; -the vector constructor is -vector.New, not vector.NewVector. -

- -

-A type that is intended to be allocated -as part of a larger struct may have an Init method -that must be called explicitly. -Conventionally, the Init method returns -the object being initialized, to make the constructor trivial: -

- -go/src/pkg/container/vector/vector.go: -
-func New(len int) *Vector {
-	return new(Vector).Init(len)
-}
-
- -

Data-Driven Programming