From 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 Mon Sep 17 00:00:00 2001
From: Michael Stapelberg godoc
does do is to display indented
text in a fixed-width font, suitable for program snippets.
The package comment for the
-fmt
package uses this to good effect.
+fmt
package uses this to good effect.
@@ -288,7 +288,7 @@ var (
-Even for private names, grouping can also indicate relationships between items, +Grouping can also indicate relationships between items, such as the fact that a set of variables is protected by a mutex.
@@ -350,7 +350,7 @@ notencoding_base64
and not encodingBase64
.
-The importer of a package will use the name to refer to its contents.
+The importer of a package will use the name to refer to its contents,
so exported names in the package can use that fact
to avoid stutter.
(Don't use the import .
notation, which can simplify
@@ -701,6 +701,7 @@ for _, value := range array {
The blank identifier has many uses, as described in a later section. +
For strings, the range
does more work for you, breaking out individual
@@ -709,7 +710,7 @@ Erroneous encodings consume one byte and produce the
replacement rune U+FFFD.
(The name (with associated builtin type) rune
is Go terminology for a
single Unicode code point.
-See the language specification
+See the language specification
for details.)
The loop
A switch can also be used to discover the dynamic type of an interface @@ -1385,8 +1386,9 @@ func (file *File) Read(buf []byte) (n int, err 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.
+any.
+To read into the first 32 bytes of a larger buffer
+buf
, slice (here used as a verb) the buffer.
n, err := f.Read(buf[0:32]) @@ -1487,7 +1489,7 @@ If the slices might grow or shrink, they should be allocated independently to avoid overwriting the next line; if not, it can be more efficient to construct the object with a single allocation. For reference, here are sketches of the two methods. -First, a line a time: +First, a line at a time:@@ -2054,10 +2056,22 @@ We pass the address of aByteSlice
because only*ByteSlice
satisfiesio.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 -invoked on pointers. This is because pointer methods can modify the -receiver; invoking them on a copy of the value would cause those -modifications to be discarded. +invoked on pointers. + ++This rule arises because pointer methods can modify the receiver; invoking +them on a value would cause the method to receive a copy of the value, so +any modifications would be discarded. +The language therefore disallows this mistake. +There is a handy exception, though. When the value is addressable, the +language takes care of the common case of invoking a pointer method on a +value by inserting the address operator automatically. +In our example, the variable
+b
is addressable, so we can call +itsWrite
method with justb.Write
. The compiler +will rewrite that to(&b).Write
for us. +By the way, the idea of using
Write
on a slice of bytes is central to the implementation ofbytes.Buffer
. @@ -2173,6 +2187,7 @@ A one-case type switch would do, but so would a type assertion. A type assertion takes an interface value and extracts from it a value of the specified explicit type. The syntax borrows from the clause opening a type switch, but with an explicit type rather than thetype
keyword: +value.(typeName) @@ -2463,6 +2478,8 @@ It has uses beyond those we've seen already.The use of a blank identifier in a
+for
range
loop is a special case of a general situation: multiple assignment. +If an assignment requires multiple values on the left side, but one of the values will not be used by the program, @@ -2937,26 +2954,19 @@ means waiting until some receiver has retrieved a value.
A buffered channel can be used like a semaphore, for instance to limit throughput. In this example, incoming requests are passed -to
handle
, which receives a value from the channel, processes -the request, and then sends a value back to the channel -to ready the "semaphore" for the next consumer. +tohandle
, which sends a value into the channel, processes +the request, and then receives a value from the channel +to ready the “semaphore” for the next consumer. The capacity of the channel buffer limits the number of -simultaneous calls toprocess
, -so during initialization we prime the channel by filling it to capacity. +simultaneous calls toprocess
.var sem = make(chan int, MaxOutstanding) func handle(r *Request) { - <-sem // Wait for active queue to drain. - process(r) // May take a long time. - sem <- 1 // Done; enable next request to run. -} - -func init() { - for i := 0; i < MaxOutstanding; i++ { - sem <- 1 - } + sem <- 1 // Wait for active queue to drain. + process(r) // May take a long time. + <-sem // Done; enable next request to run. } func Serve(queue chan *Request) { @@ -2968,10 +2978,9 @@ func Serve(queue chan *Request) {-Because data synchronization occurs on a receive from a channel -(that is, the send "happens before" the receive; see -The Go Memory Model), -acquisition of the semaphore must be on a channel receive, not a send. +Once
MaxOutstanding
handlers are executingprocess
, +any more will block trying to send into the filled channel buffer, +until one of the existing handlers finishes and receives from the buffer.@@ -2988,10 +2997,10 @@ Here's an obvious solution, but beware it has a bug we'll fix subsequently:
func Serve(queue chan *Request) { for req := range queue { - <-sem + sem <- 1 go func() { process(req) // Buggy; see explanation below. - sem <- 1 + <-sem }() } }@@ -3009,10 +3018,10 @@ to the closure in the goroutine:func Serve(queue chan *Request) { for req := range queue { - <-sem + sem <- 1 go func(req *Request) { process(req) - sem <- 1 + <-sem }(req) } }@@ -3027,11 +3036,11 @@ name, as in this example:func Serve(queue chan *Request) { for req := range queue { - <-sem req := req // Create new instance of req for the goroutine. + sem <- 1 go func() { process(req) - sem <- 1 + <-sem }() } }@@ -3278,9 +3287,18 @@ the garbage collector for bookkeeping.Library routines must often return some sort of error indication to -the caller. As mentioned earlier, Go's multivalue return makes it +the caller. +As mentioned earlier, Go's multivalue return makes it easy to return a detailed error description alongside the normal -return value. By convention, errors have type
+ +error
, +return value. +It is good style to use this feature to provide detailed error information. +For example, as we'll see,os.Open
doesn't +just return anil
pointer on failure, it also returns an +error value that describes what went wrong. ++By convention, errors have type
error
, a simple built-in interface.@@ -3292,7 +3310,12 @@ type error interface { A library writer is free to implement this interface with a richer model under the covers, making it possible not only to see the error but also to provide some context. -For example,os.Open
returns anos.PathError
. +As mentioned, alongside the usual*os.File
+return value,os.Open
also returns an +error value. +If the file is opened successfully, the error will benil
, +but when there is a problem, it will hold an +os.PathError
:// PathError records an error and the operation and -- cgit v1.2.3