From 4074795e151813f303d5500d255901c6a3a796ef Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sun, 25 Mar 2012 11:34:51 +1100 Subject: [PATCH] effective_go: cleanups and fixes Also explain the situation with recursive String methods more accurately, and clean up the code now that the fmt package is more careful. R=golang-dev, minux.ma, bradfitz CC=golang-dev https://golang.org/cl/5907047 --- doc/effective_go.html | 52 +++++++++++++++++++++++++++++---------- doc/progs/eff_bytesize.go | 18 +++++++------- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/doc/effective_go.html b/doc/effective_go.html index 80b2851837d..ed777f4bb82 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -625,9 +625,28 @@ or reading from a channel, a range clause can manage the loop.

-var m map[string]int
+for key, value := range oldMap {
+    newMap[key] = value
+}
+
+ +

+If you only need the first item in the range (the key or index), drop the second: +

+
+for key := range m {
+    if expired(key) {
+        delete(m, key)
+    }
+}
+
+ +

+If you only need the second item in the range (the value), use the blank identifier, an underscore, to discard the first: +

+
 sum := 0
-for _, value := range m {  // key is unused
+for _, value := range array {
     sum += value
 }
 
@@ -709,7 +728,7 @@ func shouldEscape(c byte) bool { Here's a comparison routine for byte arrays that uses two switch statements:
-// Compare returns an integer comparing the two byte arrays
+// Compare returns an integer comparing the two byte arrays,
 // lexicographically.
 // The result will be 0 if a == b, -1 if a < b, and +1 if a > b
 func Compare(a, b []byte) int {
@@ -1003,7 +1022,7 @@ but the rules are simple.
 Let's talk about new first.
 It's a built-in function that allocates memory, but unlike its namesakes
 in some other languages it does not initialize the memory,
-it only zeroes it.
+it only zeros it.
 That is,
 new(T) allocates zeroed storage for a new item of type
 T and returns its address, a value of type *T.
@@ -1265,7 +1284,7 @@ any.  To read into the first 32 bytes of a larger buffer
 

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, the following snippet would also read the first 32 bytes of the buffer.

     var n int
@@ -1407,7 +1426,7 @@ func offset(tz string) int {
 

To test for presence in the map without worrying about the actual value, -you can use the blank identifier, a simple underscore (_). +you can use the blank identifier (_). The blank identifier can be assigned or declared with any value of any type, with the value discarded harmlessly. For testing just presence in a map, use the blank identifier in place of the usual variable for the value. @@ -1697,13 +1716,20 @@ automatically for printing, even as part of a general type.

{{code "/doc/progs/eff_bytesize.go" `/^func.*ByteSize.*String/` `/^}/`}}

-(The float64 conversions prevent Sprintf -from recurring back through the String method for -ByteSize.) The expression YB prints as 1.00YB, while ByteSize(1e13) prints as 9.09TB.

+

+Note that it's fine to call Sprintf and friends in the +implementation of String methods, but beware of +recurring into the String method through the nested +Sprintf call using a string format +(%s, %q, %v, %x or %X). +The ByteSize implementation of String is safe +because it calls Sprintf with %f. +

+

Variables

@@ -2520,8 +2546,8 @@ system, and there's not a mutex in sight.

Another application of these ideas is to parallelize a calculation across multiple CPU cores. If the calculation can be broken into -separate pieces, it can be parallelized, with a channel to signal -when each piece completes. +separate pieces that can execute independently, it can be parallelized, +with a channel to signal when each piece completes.

Let's say we have an expensive operation to perform on a vector of items, @@ -2563,7 +2589,7 @@ func (v Vector) DoAll(u Vector) {

-The current implementation of gc (6g, etc.) +The current implementation of the Go runtime will not parallelize this code by default. It dedicates only a single core to user-level processing. An arbitrary number of goroutines can be blocked in system calls, but @@ -2989,7 +3015,7 @@ If this is too quick an explanation, see the docum for the template package for a more thorough discussion.

-And there you have it: a useful webserver in a few lines of code plus some +And there you have it: a useful web server in a few lines of code plus some data-driven HTML text. Go is powerful enough to make a lot happen in a few lines.

diff --git a/doc/progs/eff_bytesize.go b/doc/progs/eff_bytesize.go index bcfde1a5a35..b45961114dd 100644 --- a/doc/progs/eff_bytesize.go +++ b/doc/progs/eff_bytesize.go @@ -23,23 +23,23 @@ const ( func (b ByteSize) String() string { switch { case b >= YB: - return fmt.Sprintf("%.2fYB", float64(b/YB)) + return fmt.Sprintf("%.2fYB", b/YB) case b >= ZB: - return fmt.Sprintf("%.2fZB", float64(b/ZB)) + return fmt.Sprintf("%.2fZB", b/ZB) case b >= EB: - return fmt.Sprintf("%.2fEB", float64(b/EB)) + return fmt.Sprintf("%.2fEB", b/EB) case b >= PB: - return fmt.Sprintf("%.2fPB", float64(b/PB)) + return fmt.Sprintf("%.2fPB", b/PB) case b >= TB: - return fmt.Sprintf("%.2fTB", float64(b/TB)) + return fmt.Sprintf("%.2fTB", b/TB) case b >= GB: - return fmt.Sprintf("%.2fGB", float64(b/GB)) + return fmt.Sprintf("%.2fGB", b/GB) case b >= MB: - return fmt.Sprintf("%.2fMB", float64(b/MB)) + return fmt.Sprintf("%.2fMB", b/MB) case b >= KB: - return fmt.Sprintf("%.2fKB", float64(b/KB)) + return fmt.Sprintf("%.2fKB", b/KB) } - return fmt.Sprintf("%.2fB", float64(b)) + return fmt.Sprintf("%.2fB", b) } func main() {