From f10d461d937d9d2d7ee2bd0b93224bb373b7ecea Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sun, 1 Nov 2009 20:54:11 -0800 Subject: fixups to "effective go" R=rsc CC=go-dev http://go/go-review/1016020 --- doc/effective_go.html | 64 ++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 31 deletions(-) (limited to 'doc') diff --git a/doc/effective_go.html b/doc/effective_go.html index 1bd8655fa..f3f8020e6 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -228,7 +228,7 @@ Since the whole declaration is presented, such a comment can often be perfunctor
 // Error codes returned by failures to parse an expression.
 var (
-	ErrInternal = os.NewError("internal error");
+	ErrInternal      = os.NewError("internal error");
 	ErrUnmatchedLpar = os.NewError("unmatched '('");
 	ErrUnmatchedRpar = os.NewError("unmatched ')'");
 	...
@@ -255,7 +255,7 @@ var (
 Names are as important in Go as in any other language.
 In some cases they even have semantic effect: for instance,
 the visibility of a name outside a package is determined by whether its
-first character is an upper case letter.
+first character is upper case.
 It's therefore worth spending a little time talking about naming conventions
 in Go programs.
 

@@ -300,7 +300,7 @@ not container_vector and not containerVector.

The importer of a package will use the name to refer to its contents (the import . notation is intended mostly for tests and other -unusual situations), and exported names in the package can use that fact +unusual situations) and exported names in the package can use that fact to avoid stutter. For instance, the buffered reader type in the bufio package is called Reader, not BufReader, because users see it as bufio.Reader, @@ -448,7 +448,8 @@ statement, it's common to see one used to set up a local variable.

 if err := file.Chmod(0664); err != nil {
-    log.Stderr(err)
+    log.Stderr(err);
+    return err;
 }
 
@@ -519,11 +520,12 @@ 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. +If you're looping over an array, slice, string, or map, +or reading from a channel, a range clause can +manage the loop for you.

-var m map[string] int;
+var m map[string]int;
 sum := 0;
 for _, value := range m {  // key is unused
     sum += value
@@ -531,8 +533,8 @@ for _, value := range m {  // key is unused
 

-For strings, the range does more of the work for you, breaking out individual -characters by parsing the UTF-8 (erroneous encodings consume one byte and produce the +For strings, the range does more work for you, breaking out individual +Unicode characters by parsing the UTF-8 (erroneous encodings consume one byte and produce the replacement rune U+FFFD). The loop

@@ -637,7 +639,7 @@ have the corresponding type in each clause.
 
 switch t := interfaceValue.(type) {
 default:
-	fmt.Printf("unexpected type");
+	fmt.Printf("unexpected type %T", type);  // %T prints type
 case bool:
 	fmt.Printf("boolean %t\n", t);
 case int:
@@ -657,7 +659,7 @@ case *int:
 One of Go's unusual properties is that functions and methods
 can return multiple values.  This feature can be used to
 improve on a couple of clumsy idioms in C programs: in-band
-error returns (-1 for EOF for example)
+error returns (such as -1 for EOF)
 and modifying an argument.
 

@@ -1033,7 +1035,7 @@ the moment, this snippet would also read the first 32 bytes of the buffer. var n int; var err os.Error; for i := 0; i < 32; i++ { - nbytes, e := f.Read(buf[i:i+1]); + nbytes, e := f.Read(buf[i:i+1]); // Read one byte. if nbytes == 0 || e != nil { err = e; break; @@ -1083,10 +1085,10 @@ structure holding the pointer, length, and capacity) is passed by value.

Maps are a convenient and powerful built-in data structure to associate values of different types. -The key can be of type that implements equality, such as integers, -floats, strings, pointers, and interfaces (as long as the dynamic type +The key can be of any type that implements equality, such as integers, +floats, strings, pointers, and interfaces (as long as the dynamic type supports equality), but not structs, arrays or slices -because those types do not have equality defined upon them. +because those types do not have equality defined for them. Like slices, maps are a reference type. If you pass a map to a function that changes the contents of the map, the changes will be visible in the caller. @@ -1571,7 +1573,7 @@ as though the existing value has a new type. do create a new value.)

-It's an idiom of Go code to convert the +It's an idiom in Go programs to convert the type of an expression to access a different set of methods. As an example, we could use the existing type sort.IntArray to reduce the entire example @@ -1620,9 +1622,9 @@ the rest of the code is unaffected by the change of algorithm. A similar approach allows the streaming cipher algorithms in the crypto/block package to be separated from the block ciphers they chain together. -By analogy to the bufio package, +By analogy with the bufio package, they wrap a Cipher interface -and they return hash.Hash, +and return hash.Hash, io.Reader, or io.Writer interface values, not specific implementations.

@@ -1757,7 +1759,7 @@ func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) { 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, +calls f. That may seem odd but it's not that different from, say, the receiver being a channel and the method sending on the channel.

@@ -1953,8 +1955,8 @@ it would be erroneous to embed log.Logger if Job struc contained another field or method called Logger. However, if the duplicate name is never mentioned in the program outside the type definition, it is OK. This qualification provides some protection against changes made to types embedded from outside; there -is no problem if a field is added that conflicts with another field in another subtype if that field -is never used. +is no problem if a field is added that conflicts with another field in another subtype if neither field +is ever used.

@@ -1986,11 +1988,11 @@ high-level approach, using channels to control access makes it easier to write clear, correct programs.

-Another way to think about this model is to consider a typical single-threaded +One way to think about this model is to consider a typical single-threaded program running on one CPU. It has no need for synchronization primitives. Now run another such instance; it too needs no synchronization. Now let those two communicate; if the communication is the synchronizer, there's still no need -for other synchronization. Consider Unix pipelines: they fit this model +for other synchronization. Unix pipelines, for example, fit this model perfectly. Although Go's approach to concurrency originates in Hoare's Communicating Sequential Processes (CSP), it can also be seen as a type-safe generalization of Unix pipes. @@ -2036,7 +2038,7 @@ func Announce(message string, delay int64) { }

-In Go function literals are closures: the implementation makes +In Go, function literals are closures: the implementation makes sure the variables referred to by the function survive as long as they are active.

These examples aren't too practical because the functions have no way of signaling @@ -2086,7 +2088,7 @@ value has been copied to the buffer. A buffered channel can be used like a semaphore, for instance to limit throughput. In this example, incoming requests are passed to handle, which sends a value into the channel, processes -the request, and then receives a value out of the channel. +the request, and then receives a value from the channel. The capacity of the channel buffer limits the number of simultaneous calls to process.

@@ -2166,7 +2168,7 @@ func sum(a []int) (s int) { request := &Request{[]int{3, 4, 5}, sum, make(chan int)} // Send request -client Requests <- request; +clientRequests <- request; // Wait for response. fmt.Printf("answer: %d\n", <-request.resultChan);
@@ -2194,15 +2196,15 @@ separate pieces, it can be parallelized, with a channel to signal when each piece completes.

-Let's say we have an expensive operation to perform on an array of items, +Let's say we have an expensive operation to perform on a vector of items, and that the value of the operation on each item is independent, as in this idealized example.

-type Vec []float64
+type Vector []float64
 
 // Apply the operation to n elements of v starting at i.
-func (v Vec) DoSome(i, n int, u Vec, c chan int) {
+func (v Vector) DoSome(i, n int, u Vector, c chan int) {
     for ; i < n; i++ {
         v[i] += u.Op(v[i])
     }
@@ -2218,7 +2220,7 @@ launching all the goroutines.
 
 const NCPU = 4	// number of CPU cores
 
-func (v Vec) DoAll(u Vec) {
+func (v Vector) DoAll(u Vector) {
     c := make(chan int, NCPU);  // Buffering optional but sensible.
     for i := 0; i < NCPU; i++ {
         go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c);
@@ -2235,7 +2237,7 @@ func (v Vec) DoAll(u Vec) {
 

A leaky buffer

-The tools of concurrent programming can often make non-concurrent +The tools of concurrent programming can even make non-concurrent ideas easier to express. Here's an example abstracted from an RPC package. The client goroutine loops receiving data from some source, perhaps a network. To avoid allocating and freeing buffers, it keeps -- cgit v1.2.3