From: Rob Pike range
does more work for you, breaking out individual
Unicode code points by parsing the UTF-8.
Erroneous encodings consume one byte and produce the
-replacement rune U+FFFD. The loop
+replacement rune U+FFFD.
+(The name (with associated builtin type) rune
is Go terminology for a
+single Unicode code point.
+See the language specification
+for details.)
+The loop
for pos, char := range "æ¥æ¬\x80èª" { // \x80 is an illegal UTF-8 encoding @@ -1596,8 +1601,7 @@ fmt.Println("Hello", 23) fmt.Println(fmt.Sprint("Hello ", 23))
-As mentioned in
-the Tour, fmt.Fprint
+The formatted print functions fmt.Fprint
and friends take as a first argument any object
that implements the io.Writer
interface; the variables os.Stdout
and os.Stderr
are familiar instances.
@@ -1663,8 +1667,10 @@ map[string] int{"CST":-21600, "PST":-28800, "EST":-18000, "UTC":0, "MST":-25200}
(Note the ampersands.)
That quoted string format is also available through %q
when
-applied to a value of type string
or []byte
;
-the alternate format %#q
will use backquotes instead if possible.
+applied to a value of type string
or []byte
.
+The alternate format %#q
will use backquotes instead if possible.
+(The %q
format also applies to integers and runes, producing a
+single-quoted rune constant.)
Also, %x
works on strings, byte arrays and byte slices as well as
on integers, generating a long hexadecimal string, and with
a space in the format (% x
) it puts spaces between the bytes.
@@ -1762,7 +1768,7 @@ is different from our custom Append
function above.
Schematically, it's like this:
-func append(slice []T, elements...T) []T +func append(slice []T, elements...T) []T
where T is a placeholder for any given type. You can't
@@ -1810,7 +1816,7 @@ would be wrong; y
is not of type int
.
Although it doesn't look superficially very different from
initialization in C or C++, initialization in Go is more powerful.
Complex structures can be built during initialization and the ordering
-issues between initialized objects in different packages are handled
+issues among initialized objects, even among different packages, are handled
correctly.
-The ability to attach a method such as String
to a
-type makes it possible for such values to format themselves
-automatically for printing, even as part of a general type.
+The ability to attach a method such as String
to any
+user-defined type makes it possible for arbitrary values to format themselves
+automatically for printing.
+Although you'll see it most often applied to structs, this technique is also useful for
+scalar types such as floating-point types like ByteSize
.
@@ -1909,7 +1917,8 @@ func init() {
-Methods can be defined for any named type that is not a pointer or an interface;
+As we saw with ByteSize
,
+methods can be defined for any named type (except a pointer or an interface);
the receiver does not have to be a struct.
@@ -1970,7 +1979,7 @@ modifications to be discarded.
By the way, the idea of using Write
on a slice of bytes
-is implemented by bytes.Buffer
.
+is central to the implementation of bytes.Buffer
.
func ArgServer() { - for _, s := range os.Args { - fmt.Println(s) - } + fmt.Println(os.Args) }
@@ -2243,9 +2250,7 @@ to have the right signature.
// Argument server. func ArgServer(w http.ResponseWriter, req *http.Request) { - for _, s := range os.Args { - fmt.Fprintln(w, s) - } + fmt.Fprintln(w, os.Args) }
@@ -2400,8 +2405,8 @@ log to the Job
:
job.Log("starting now...")
-The Logger
is a regular field of the struct and we can initialize
-it in the usual way with a constructor,
+The Logger
is a regular field of the Job
struct,
+so we can initialize it in the usual way inside the constructor for Job
, like this,
func NewJob(command string, logger *log.Logger) *Job { @@ -2416,10 +2421,12 @@ job := &Job{command, log.New(os.Stderr, "Job: ", log.Ldate)}
If we need to refer to an embedded field directly, the type name of the field,
-ignoring the package qualifier, serves as a field name. If we needed to access the
+ignoring the package qualifier, serves as a field name, as it did
+in the Read
method of our ReaderWriter
struct.
+Here, if we needed to access the
*log.Logger
of a Job
variable job
,
-we would write job.Logger
.
-This would be useful if we wanted to refine the methods of Logger
.
+we would write job.Logger
,
+which would be useful if we wanted to refine the methods of Logger
.
func (job *Job) Logf(format string, args ...interface{}) { @@ -2535,7 +2542,8 @@ completion. For that, we need channels.Channels
-Like maps, channels are allocated with
@@ -2545,7 +2553,7 @@ cj := make(chan int, 0) // unbuffered channel of integers cs := make(chan *os.File, 100) // buffered channel of pointers to Filesmake
. +Like maps, channels are allocated withmake
, and +the resulting value acts as a reference to an underlying data structure. If an optional integer parameter is provided, it sets the buffer size for the channel. The default is zero, for an unbuffered or synchronous channel.
-Channels combine communication—the exchange of a value—with +Unbuffered channels combine communication—the exchange of a value—with synchronization—guaranteeing that two calculations (goroutines) are in a known state.
@@ -2741,6 +2749,17 @@ of logical CPUs on the local machine. Again, this requirement is expected to be retired as the scheduling and run-time improve. ++Be sure not to confuse the ideas of concurrencyâstructuring a program +as independently executing componentsâand parallelismâexecuting +calculations in parallel for efficiency on multiple CPUs. +Although the concurrency features of Go can make some problems easy +to structure as parallel computations, Go is a concurrent language, +not a parallel one, and not all parallelization problems fit Go's model. +For a discussion of the distinction, see the talk cited in +this +blog post. +
@@ -2857,7 +2876,7 @@ it is much more informative than the plain
When feasible, error strings should identify their origin, such as by having
-a prefix naming the package that generated the error. For example, in package
+a prefix naming the operation or package that generated the error. For example, in package
image
, the string representation for a decoding error due to an
unknown format is "image: unknown format".
panic
at the end of a function and
-suppresses the usual check for a return
statement.
+happened, such as exiting an infinite loop.
@@ -3016,7 +3033,7 @@ With our recovery pattern in place, the do
function (and anything it calls) can get out of any bad situation
cleanly by calling panic
. We can use that idea to
simplify error handling in complex software. Let's look at an
-idealized excerpt from the regexp
package, which reports
+idealized version of a regexp
package, which reports
parsing errors by calling panic
with a local
error type. Here's the definition of Error
,
an error
method, and the Compile
function.
@@ -3057,18 +3074,27 @@ to err
, that the problem was a parse error by asserting
that it has the local type Error
.
If it does not, the type assertion will fail, causing a run-time error
that continues the stack unwinding as though nothing had interrupted
-it. This check means that if something unexpected happens, such
+it.
+This check means that if something unexpected happens, such
as an index out of bounds, the code will fail even though we
are using panic
and recover
to handle
-user-triggered errors.
+parse errors.
-With error handling in place, the error
method
+With error handling in place, the error
method (because it's a
+method bound to a type, it's fine, even natural, for it to have the same name
+as the builtin error
type)
makes it easy to report parse errors without worrying about unwinding
-the parse stack by hand.
+the parse stack by hand:
+if pos==0 { + re.error("'*' illegal at start of expression") +} ++
Useful though this pattern is, it should be used only within a package.
Parse
turns its internal panic
calls into