diff options
Diffstat (limited to 'doc/effective_go.html')
-rw-r--r-- | doc/effective_go.html | 161 |
1 files changed, 118 insertions, 43 deletions
diff --git a/doc/effective_go.html b/doc/effective_go.html index 41a7b8af9..26e317b5d 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -207,7 +207,7 @@ have a doc comment. </p> <p> -Doc comments work best as complete English sentences, which allow +Doc comments work best as complete sentences, which allow a wide variety of automated presentations. The first sentence should be a one-sentence summary that starts with the name being declared. @@ -463,7 +463,7 @@ statement, it's common to see one used to set up a local variable. <pre> if err := file.Chmod(0664); err != nil { - log.Stderr(err) + log.Print(err) return err } </pre> @@ -794,7 +794,7 @@ func Contents(filename string) (string, os.Error) { buf := make([]byte, 100) for { n, err := f.Read(buf[0:]) - result = bytes.Add(result, buf[0:n]) + result = append(result, buf[0:n]...) // append is discussed later. if err != nil { if err == os.EOF { break @@ -815,7 +815,7 @@ which is much clearer than placing it at the end of the function. </p> <p> -The arguments to the deferred function (which includes the receiver if +The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the <i>defer</i> executes, not when the <i>call</i> executes. Besides avoiding worries about variables changing values as the function executes, this means @@ -1218,6 +1218,11 @@ func Append(slice, data[]byte) []byte { We must return the slice afterwards because, although <code>Append</code> can modify the elements of <code>slice</code>, the slice itself (the run-time data structure holding the pointer, length, and capacity) is passed by value. +<p> +The idea of appending to a slice is so useful it's captured by the +<code>append</code> built-in function. To understand that function's +design, though, we need a little more information, so we'll return +to it later. </p> @@ -1288,7 +1293,7 @@ func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } - log.Stderr("unknown time zone", tz) + log.Println("unknown time zone", tz) return 0 } </pre> @@ -1326,13 +1331,15 @@ You don't need to provide a format string. For each of <code>Printf</code>, <code>Fprintf</code> and <code>Sprintf</code> there is another pair of functions, for instance <code>Print</code> and <code>Println</code>. These functions do not take a format string but instead generate a default -format for each argument. The <code>ln</code> version also inserts a blank -between arguments if neither is a string and appends a newline to the output. +format for each argument. The <code>Println</code> versions also insert a blank +between arguments and append a newline to the output while +the <code>Print</code> versions add blanks only if the operand on neither side is a string. In this example each line produces the same output. </p> <pre> fmt.Printf("Hello %d\n", 23) fmt.Fprint(os.Stdout, "Hello ", 23, "\n") +fmt.Println("Hello", 23) fmt.Println(fmt.Sprint("Hello ", 23)) </pre> <p> @@ -1453,16 +1460,20 @@ Within the function <code>Printf</code>, <code>v</code> acts like a variable of <code>[]interface{}</code> but if it is passed to another variadic function, it acts like a regular list of arguments. Here is the implementation of the -function <code>log.Stderr</code> we used above. It passes its arguments directly to +function <code>log.Println</code> we used above. It passes its arguments directly to <code>fmt.Sprintln</code> for the actual formatting. </p> <pre> -// Stderr is a helper function for easy logging to stderr. It is analogous to Fprintln(os.Stderr). -func Stderr(v ...interface{}) { - stderr.Output(2, fmt.Sprintln(v)) // Output takes parameters (int, string) +// Println prints to the standard logger in the manner of fmt.Println. +func Println(v ...interface{}) { + std.Output(2, fmt.Sprintln(v...)) // Output takes parameters (int, string) } </pre> <p> +We write <code>...</code> after <code>v</code> in the nested call to <code>Sprintln</code> to tell the +compiler to treat <code>v</code> as a list of arguments; otherwise it would just pass +<code>v</code> as a single slice argument. +<p> There's even more to printing than we've covered here. See the <code>godoc</code> documentation for package <code>fmt</code> for the details. </p> @@ -1482,6 +1493,47 @@ func Min(a ...int) int { } </pre> +<h3 id="append">Append</h3> +<p> +Now we have the missing piece we needed to explain the design of +the <code>append</code> built-in function. The signature of <code>append</code> +is different from our custom <code>Append</code> function above. +Schematically, it's like this: +<pre> +func append(slice []<i>T</i>, elements...T) []<i>T</i> +</pre> +where <i>T</i> is a placeholder for any given type. You can't +actually write a function in Go where the type <code>T</code> +is determined by the caller. +That's why <code>append</code> is built in: it needs support from the +compiler. +<p> +What <code>append</code> does is append the elements to the end of +the slice and return the result. The result needs to be returned +because, as with our hand-written <code>Append</code>, the underlying +array may change. This simple example +<pre> +x := []int{1,2,3} +x = append(x, 4, 5, 6) +fmt.Println(x) +</pre> +prints <code>[1 2 3 4 5 6]</code>. So <code>append</code> works a +little like <code>Printf</code>, collecting an arbitrary number of +arguments. +<p> +But what if we wanted to do what our <code>Append</code> does and +append a slice to a slice? Easy: use <code>...</code> at the call +site, just as we did in the call to <code>Output</code> above. This +snippet produces identical output to the one above. +<pre> +x := []int{1,2,3} +y := []int{4,5,6} +x = append(x, y...) +fmt.Println(x) +</pre> +Without that <code>...</code>, it wouldn't compile because the types +would be wrong; <code>y</code> is not of type <code>int</code>. + <h2 id="initialization">Initialization</h2> <p> @@ -1537,26 +1589,29 @@ automatically for printing, even as part of a general type. func (b ByteSize) String() string { switch { case b >= YB: - return fmt.Sprintf("%.2fYB", b/YB) + return fmt.Sprintf("%.2fYB", float64(b/YB)) case b >= ZB: - return fmt.Sprintf("%.2fZB", b/ZB) + return fmt.Sprintf("%.2fZB", float64(b/ZB)) case b >= EB: - return fmt.Sprintf("%.2fEB", b/EB) + return fmt.Sprintf("%.2fEB", float64(b/EB)) case b >= PB: - return fmt.Sprintf("%.2fPB", b/PB) + return fmt.Sprintf("%.2fPB", float64(b/PB)) case b >= TB: - return fmt.Sprintf("%.2fTB", b/TB) + return fmt.Sprintf("%.2fTB", float64(b/TB)) case b >= GB: - return fmt.Sprintf("%.2fGB", b/GB) + return fmt.Sprintf("%.2fGB", float64(b/GB)) case b >= MB: - return fmt.Sprintf("%.2fMB", b/MB) + return fmt.Sprintf("%.2fMB", float64(b/MB)) case b >= KB: - return fmt.Sprintf("%.2fKB", b/KB) + return fmt.Sprintf("%.2fKB", float64(b/KB)) } - return fmt.Sprintf("%.2fB", b) + return fmt.Sprintf("%.2fB", float64(b)) } </pre> <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>, while <code>ByteSize(1e13)</code> prints as <code>9.09TB</code>. </p> @@ -1849,10 +1904,18 @@ that implements <code>Handler</code> can serve HTTP requests. </p> <pre> type Handler interface { - ServeHTTP(*Conn, *Request) + ServeHTTP(ResponseWriter, *Request) } </pre> <p> +<code>ResponseWriter</code> is itself an interface that provides access +to the methods needed to return the response to the client. +Those methods include the standard <code>Write</code> method, so an +<code>http.ResponseWriter</code> can be used wherever an <code>io.Writer</code> +can be used. +<code>Request</code> is a struct containing a parsed representation +of the request from the client. +<p> For brevity, let's ignore POSTs and assume HTTP requests are always GETs; that simplification does not affect the way the handlers are set up. Here's a trivial but complete implementation of a handler to @@ -1865,13 +1928,14 @@ type Counter struct { n int } -func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) { +func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) { ctr.n++ - fmt.Fprintf(c, "counter = %d\n", ctr.n) + fmt.Fprintf(w, "counter = %d\n", ctr.n) } </pre> <p> -(Keeping with our theme, note how <code>Fprintf</code> can print to an HTTP connection.) +(Keeping with our theme, note how <code>Fprintf</code> can print to an +<code>http.ResponseWriter</code>.) For reference, here's how to attach such a server to a node on the URL tree. <pre> import "http" @@ -1887,9 +1951,9 @@ But why make <code>Counter</code> a struct? An integer is all that's needed. // Simpler counter server. type Counter int -func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) { +func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) { *ctr++ - fmt.Fprintf(c, "counter = %d\n", *ctr) + fmt.Fprintf(w, "counter = %d\n", *ctr) } </pre> <p> @@ -1901,9 +1965,9 @@ has been visited? Tie a channel to the web page. // (Probably want the channel to be buffered.) type Chan chan *http.Request -func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) { +func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) { ch <- req - fmt.Fprint(c, "notification sent") + fmt.Fprint(w, "notification sent") } </pre> <p> @@ -1930,11 +1994,11 @@ The <code>http</code> package contains this code: // ordinary functions as HTTP handlers. If f is a function // with the appropriate signature, HandlerFunc(f) is a // Handler object that calls f. -type HandlerFunc func(*Conn, *Request) +type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(c, req). -func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) { - f(c, req) +func (f HandlerFunc) ServeHTTP(w ResponseWriter, req *Request) { + f(w, req) } </pre> <p> @@ -1950,9 +2014,9 @@ to have the right signature. </p> <pre> // Argument server. -func ArgServer(c *http.Conn, req *http.Request) { +func ArgServer(w http.ResponseWriter, req *http.Request) { for i, s := range os.Args { - fmt.Fprintln(c, s) + fmt.Fprintln(w, s) } } </pre> @@ -2014,7 +2078,7 @@ two methods explicitly, but it's easier and more evocative to embed the two interfaces to form the new one, like this: </p> <pre> -// ReadWrite is the interface that groups the basic Read and Write methods. +// ReadWriter is the interface that combines the Reader and Writer interfaces. type ReadWriter interface { Reader Writer @@ -2119,7 +2183,7 @@ func NewJob(command string, logger *log.Logger) *Job { or with a composite literal, </p> <pre> -job := &Job{command, log.New(os.Stderr, nil, "Job: ", log.Ldate)} +job := &Job{command, log.New(os.Stderr, "Job: ", log.Ldate)} </pre> <p> If we need to refer to an embedded field directly, the type name of the field, @@ -2603,7 +2667,7 @@ func CubeRoot(x float64) float64 { } } // A million iterations has not converged; something is wrong. - panic(fmt.Sprintf("CubeRoot(%g) did not converge", x) + panic(fmt.Sprintf("CubeRoot(%g) did not converge", x)) } </pre> @@ -2654,14 +2718,14 @@ inside a server without killing the other executing goroutines. <pre> func server(workChan <-chan *Work) { for work := range workChan { - safelyDo(work) + go safelyDo(work) } } func safelyDo(work *Work) { defer func() { if err := recover(); err != nil { - log.Stderr("work failed:", err) + log.Println("work failed:", err) } }() do(work) @@ -2728,7 +2792,7 @@ user-triggered errors. </p> <p> -With this error handling in place, the <code>error</code> method +With error handling in place, the <code>error</code> method makes it easy to report parse errors without worrying about unwinding the parse stack by hand. </p> @@ -2740,6 +2804,17 @@ Useful though this pattern is, it should be used only within a package. to its client. That is a good rule to follow. </p> +<p> +By the way, this re-panic idiom changes the panic value if an actual +error occurs. However, both the original and new failures will be +presented in the crash report, so the root cause of the problem will +still be visible. Thus this simple re-panic approach is usually +sufficient—it's a crash after all—but if you want to +display only the original value, you can write a little more code to +filter unexpected problems and re-panic with the original error. +That's left as an exercise for the reader. +</p> + <h2 id="web_server">A web server</h2> @@ -2789,12 +2864,12 @@ func main() { } } -func QR(c *http.Conn, req *http.Request) { - templ.Execute(req.FormValue("s"), c) +func QR(w http.ResponseWriter, req *http.Request) { + templ.Execute(req.FormValue("s"), w) } -func UrlHtmlFormatter(w io.Writer, v interface{}, fmt string) { - template.HTMLEscape(w, []byte(http.URLEscape(v.(string)))) +func UrlHtmlFormatter(w io.Writer, fmt string, v ...interface{}) { + template.HTMLEscape(w, []byte(http.URLEscape(v[0].(string)))) } |