mirror of
https://github.com/golang/go
synced 2024-11-21 15:34:45 -07:00
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
This commit is contained in:
parent
73b5eb38c1
commit
4074795e15
@ -625,9 +625,28 @@ or reading from a channel, a <code>range</code> clause can
|
|||||||
manage the loop.
|
manage the loop.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
var m map[string]int
|
for key, value := range oldMap {
|
||||||
|
newMap[key] = value
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you only need the first item in the range (the key or index), drop the second:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
for key := range m {
|
||||||
|
if expired(key) {
|
||||||
|
delete(m, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you only need the second item in the range (the value), use the <em>blank identifier</em>, an underscore, to discard the first:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
sum := 0
|
sum := 0
|
||||||
for _, value := range m { // key is unused
|
for _, value := range array {
|
||||||
sum += value
|
sum += value
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -709,7 +728,7 @@ func shouldEscape(c byte) bool {
|
|||||||
Here's a comparison routine for byte arrays that uses two
|
Here's a comparison routine for byte arrays that uses two
|
||||||
<code>switch</code> statements:
|
<code>switch</code> statements:
|
||||||
<pre>
|
<pre>
|
||||||
// Compare returns an integer comparing the two byte arrays
|
// Compare returns an integer comparing the two byte arrays,
|
||||||
// lexicographically.
|
// lexicographically.
|
||||||
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b
|
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b
|
||||||
func Compare(a, b []byte) int {
|
func Compare(a, b []byte) int {
|
||||||
@ -1003,7 +1022,7 @@ but the rules are simple.
|
|||||||
Let's talk about <code>new</code> first.
|
Let's talk about <code>new</code> first.
|
||||||
It's a built-in function that allocates memory, but unlike its namesakes
|
It's a built-in function that allocates memory, but unlike its namesakes
|
||||||
in some other languages it does not <em>initialize</em> the memory,
|
in some other languages it does not <em>initialize</em> the memory,
|
||||||
it only <em>zeroes</em> it.
|
it only <em>zeros</em> it.
|
||||||
That is,
|
That is,
|
||||||
<code>new(T)</code> allocates zeroed storage for a new item of type
|
<code>new(T)</code> allocates zeroed storage for a new item of type
|
||||||
<code>T</code> and returns its address, a value of type <code>*T</code>.
|
<code>T</code> and returns its address, a value of type <code>*T</code>.
|
||||||
@ -1265,7 +1284,7 @@ any. To read into the first 32 bytes of a larger buffer
|
|||||||
</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, the following snippet would also read the first 32 bytes of the buffer.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
var n int
|
var n int
|
||||||
@ -1407,7 +1426,7 @@ func offset(tz string) int {
|
|||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
To test for presence in the map without worrying about the actual value,
|
To test for presence in the map without worrying about the actual value,
|
||||||
you can use the <em>blank identifier</em>, a simple underscore (<code>_</code>).
|
you can use the blank identifier (<code>_</code>).
|
||||||
The blank identifier can be assigned or declared with any value of any type, with the
|
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
|
value discarded harmlessly. For testing just presence in a map, use the blank
|
||||||
identifier in place of the usual variable for the value.
|
identifier in place of the usual variable for the value.
|
||||||
@ -1697,13 +1716,20 @@ automatically for printing, even as part of a general type.
|
|||||||
</p>
|
</p>
|
||||||
{{code "/doc/progs/eff_bytesize.go" `/^func.*ByteSize.*String/` `/^}/`}}
|
{{code "/doc/progs/eff_bytesize.go" `/^func.*ByteSize.*String/` `/^}/`}}
|
||||||
<p>
|
<p>
|
||||||
(The <code>float64</code> conversions prevent <code>Sprintf</code>
|
|
||||||
from recurring back through the <code>String</code> method for
|
|
||||||
<code>ByteSize</code>.)
|
|
||||||
The expression <code>YB</code> prints as <code>1.00YB</code>,
|
The expression <code>YB</code> prints as <code>1.00YB</code>,
|
||||||
while <code>ByteSize(1e13)</code> prints as <code>9.09TB</code>.
|
while <code>ByteSize(1e13)</code> prints as <code>9.09TB</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note that it's fine to call <code>Sprintf</code> and friends in the
|
||||||
|
implementation of <code>String</code> methods, but beware of
|
||||||
|
recurring into the <code>String</code> method through the nested
|
||||||
|
<code>Sprintf</code> call using a string format
|
||||||
|
(<code>%s</code>, <code>%q</code>, <code>%v</code>, <code>%x</code> or <code>%X</code>).
|
||||||
|
The <code>ByteSize</code> implementation of <code>String</code> is safe
|
||||||
|
because it calls <code>Sprintf</code> with <code>%f</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="variables">Variables</h3>
|
<h3 id="variables">Variables</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -2520,8 +2546,8 @@ system, and there's not a mutex in sight.
|
|||||||
<p>
|
<p>
|
||||||
Another application of these ideas is to parallelize a calculation
|
Another application of these ideas is to parallelize a calculation
|
||||||
across multiple CPU cores. If the calculation can be broken into
|
across multiple CPU cores. If the calculation can be broken into
|
||||||
separate pieces, it can be parallelized, with a channel to signal
|
separate pieces that can execute independently, it can be parallelized,
|
||||||
when each piece completes.
|
with a channel to signal when each piece completes.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Let's say we have an expensive operation to perform on a vector of items,
|
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) {
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The current implementation of <code>gc</code> (<code>6g</code>, etc.)
|
The current implementation of the Go runtime
|
||||||
will not parallelize this code by default.
|
will not parallelize this code by default.
|
||||||
It dedicates only a single core to user-level processing. An
|
It dedicates only a single core to user-level processing. An
|
||||||
arbitrary number of goroutines can be blocked in system calls, but
|
arbitrary number of goroutines can be blocked in system calls, but
|
||||||
@ -2989,7 +3015,7 @@ If this is too quick an explanation, see the <a href="/pkg/text/template/">docum
|
|||||||
for the template package for a more thorough discussion.
|
for the template package for a more thorough discussion.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
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.
|
data-driven HTML text.
|
||||||
Go is powerful enough to make a lot happen in a few lines.
|
Go is powerful enough to make a lot happen in a few lines.
|
||||||
</p>
|
</p>
|
||||||
|
@ -23,23 +23,23 @@ const (
|
|||||||
func (b ByteSize) String() string {
|
func (b ByteSize) String() string {
|
||||||
switch {
|
switch {
|
||||||
case b >= YB:
|
case b >= YB:
|
||||||
return fmt.Sprintf("%.2fYB", float64(b/YB))
|
return fmt.Sprintf("%.2fYB", b/YB)
|
||||||
case b >= ZB:
|
case b >= ZB:
|
||||||
return fmt.Sprintf("%.2fZB", float64(b/ZB))
|
return fmt.Sprintf("%.2fZB", b/ZB)
|
||||||
case b >= EB:
|
case b >= EB:
|
||||||
return fmt.Sprintf("%.2fEB", float64(b/EB))
|
return fmt.Sprintf("%.2fEB", b/EB)
|
||||||
case b >= PB:
|
case b >= PB:
|
||||||
return fmt.Sprintf("%.2fPB", float64(b/PB))
|
return fmt.Sprintf("%.2fPB", b/PB)
|
||||||
case b >= TB:
|
case b >= TB:
|
||||||
return fmt.Sprintf("%.2fTB", float64(b/TB))
|
return fmt.Sprintf("%.2fTB", b/TB)
|
||||||
case b >= GB:
|
case b >= GB:
|
||||||
return fmt.Sprintf("%.2fGB", float64(b/GB))
|
return fmt.Sprintf("%.2fGB", b/GB)
|
||||||
case b >= MB:
|
case b >= MB:
|
||||||
return fmt.Sprintf("%.2fMB", float64(b/MB))
|
return fmt.Sprintf("%.2fMB", b/MB)
|
||||||
case b >= KB:
|
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() {
|
func main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user