summaryrefslogtreecommitdiff
path: root/doc/effective_go.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/effective_go.html')
-rw-r--r--doc/effective_go.html161
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 &gt;= YB:
- return fmt.Sprintf("%.2fYB", b/YB)
+ return fmt.Sprintf("%.2fYB", float64(b/YB))
case b &gt;= ZB:
- return fmt.Sprintf("%.2fZB", b/ZB)
+ return fmt.Sprintf("%.2fZB", float64(b/ZB))
case b &gt;= EB:
- return fmt.Sprintf("%.2fEB", b/EB)
+ return fmt.Sprintf("%.2fEB", float64(b/EB))
case b &gt;= PB:
- return fmt.Sprintf("%.2fPB", b/PB)
+ return fmt.Sprintf("%.2fPB", float64(b/PB))
case b &gt;= TB:
- return fmt.Sprintf("%.2fTB", b/TB)
+ return fmt.Sprintf("%.2fTB", float64(b/TB))
case b &gt;= GB:
- return fmt.Sprintf("%.2fGB", b/GB)
+ return fmt.Sprintf("%.2fGB", float64(b/GB))
case b &gt;= MB:
- return fmt.Sprintf("%.2fMB", b/MB)
+ return fmt.Sprintf("%.2fMB", float64(b/MB))
case b &gt;= 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 &lt;- 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 := &amp;Job{command, log.New(os.Stderr, nil, "Job: ", log.Ldate)}
+job := &amp;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&mdash;it's a crash after all&mdash;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))))
}