diff options
-rw-r--r-- | doc/effective_go.html | 170 |
1 files changed, 105 insertions, 65 deletions
diff --git a/doc/effective_go.html b/doc/effective_go.html index ec40ce87a..73b91ca80 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -628,6 +628,28 @@ func Compare(a, b []byte) int { } </pre> +<p> +A switch can also be used to discover the dynamic type of an interface +variable. Such a <em>type switch</em> uses the syntax of a type +assertion with the keyword <code>type</code> inside the parentheses. +If the switch declares a variable in the expression, the variable will +have the corresponding type in each clause. +</p> +<pre> +switch t := interfaceValue.(type) { +default: + fmt.Printf("unexpected type"); +case bool: + fmt.Printf("boolean %t\n", t); +case int: + fmt.Printf("integer %d\n", t); +case *bool: + fmt.Printf("pointer to boolean %t\n", *t); +case *int: + fmt.Printf("pointer to integer %d\n", *t); +} +</pre> + <h2 id="functions">Functions</h2> <h3 id="multiple-returns">Multiple return values</h3> @@ -1350,75 +1372,124 @@ By the way, the idea of using <code>Write</code> on a slice of bytes is implemented by <code>bytes.Buffer</code>. </p> -<h2>More to come</h2> +<h2>Interfaces</h2> <!--- +<h3 id="accept-interface-values">Accept interface values</h3> -<h2 id="idioms">Idioms</h2> +buffered i/o takes a Reader, not an os.File. XXX +<h3 id="return-interface-values">Return interface values</h3> -<h3 id="buffer-slice">Use parallel assignment to slice a buffer</h3> +<p> +If a type exists only to implement an interface +and has no exported methods beyond that interface, +there is no need to publish the type itself. +Instead, write a constructor that returns an interface value. +</p> -<pre> -header, body, checksum := buf[0:20], buf[20:n-4], buf[n-4:n]; -</pre> +<p> +For example, both <code>crc32.NewIEEE()</code> and <code>adler32.New()</code> +return type <code>hash.Hash32</code>. +Substituting the CRC-32 algorithm for Adler-32 in a Go program +requires only changing the constructor call: +the rest of the code is unaffected by the change of algorithm. +</p> -<h2 id="errors">Errors</h2> +<h3 id="asdf">Use interface adapters to expand an implementation</h3> -<h3 id="error-returns">Return <code>os.Error</code>, not <code>bool</code></h3> +XXX -<p> -Especially in libraries, functions tend to have multiple error modes. -Instead of returning a boolean to signal success, -return an <code>os.Error</code> that describes the failure. -Even if there is only one failure mode now, -there may be more later. -</p> +<h3 id="fdsa">Use anonymous fields to incorporate an implementation</h3> -<h3 id="error-context">Return structured errors</h3> +XXX +---> -Implementations of <code>os.Error</code> should -describe the error and provide context. -For example, <code>os.Open</code> returns an <code>os.PathError</code>: +<h2 id="errors">Errors</h2> -<a href="http://go/godoc/src/pkg/os/file.go">http://go/godoc/src/pkg/os/file.go</a>: +<p> +Library routines must often return some sort of error indication to +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 <code>os.Error</code>, +a simple interface. +</p> +<pre> +type Error interface { + String() string; +} +</pre> +<p> +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, <code>os.Open</code> returns an <code>os.PathError</code>. +</p> <pre> // PathError records an error and the operation and // file path that caused it. type PathError struct { - Op string; - Path string; - Error Error; + Op string; // "open", "unlink", etc. + Path string; // The associated file. + Error Error; // Returned by the system call. } func (e *PathError) String() string { - return e.Op + " " + e.Path + ": " + e.Error.String(); + return e.Op + " " + e.Path + ": " + e.Error.String(); } </pre> - <p> -<code>PathError</code>'s <code>String</code> formats -the error nicely, including the operation and file name -tha failed; just printing the error generates a -message, such as +<code>PathError</code>'s <code>String</code> generates +a string like this: </p> <pre> open /etc/passwx: no such file or directory </pre> <p> -that is useful even if printed far from the call that -triggered it. +Such an error, which includes the problematic file name, the +operation, and the operating system error it triggered, is useful even +if printed far from the call that caused it; +it is much more informative than the plain +"no such file or directory". </p> <p> Callers that care about the precise error details can -use a type switch or a type guard to look for specific +use a type switch or a type assertion to look for specific errors and extract details. For <code>PathErrors</code> this might include examining the internal <code>Error</code> -to see if it is <code>os.EPERM</code> or <code>os.ENOENT</code>, -for instance. +field for recoverable failures. </p> +<pre> +for try := 0; try < 2; try++ { + file, err := os.Open(filename, os.O_RDONLY, 0); + if err == nil { + return + } + if e, ok := err.(*os.PathError); ok && e.Error == os.ENOSPC { + deleteTempFiles(); // Recover some space. + continue + } + return +} +</pre> + +<h2>Testing</h2> + +<h2>More to come</h2> + +<!--- + +<h2 id="idioms">Idioms</h2> + + +<h3 id="buffer-slice">Use parallel assignment to slice a buffer</h3> + +<pre> +header, body, checksum := buf[0:20], buf[20:n-4], buf[n-4:n]; +</pre> + <h2 id="types">Programmer-defined types</h2> <p>Packages that export only a single type can @@ -1443,37 +1514,6 @@ func New(len int) *Vector { </pre> -<h2 id="interfaces">Interfaces</h2> - -<h3 id="accept-interface-values">Accept interface values</h3> - -buffered i/o takes a Reader, not an os.File. XXX - -<h3 id="return-interface-values">Return interface values</h3> - -<p> -If a type exists only to implement an interface -and has no exported methods beyond that interface, -there is no need to publish the type itself. -Instead, write a constructor that returns an interface value. -</p> - -<p> -For example, both <code>crc32.NewIEEE()</code> and <code>adler32.New()</code> -return type <code>hash.Hash32</code>. -Substituting the CRC-32 algorithm for Adler-32 in a Go program -requires only changing the constructor call: -the rest of the code is unaffected by the change of algorithm. -</p> - -<h3 id="asdf">Use interface adapters to expand an implementation</h3> - -XXX - -<h3 id="fdsa">Use anonymous fields to incorporate an implementation</h3> - -XXX - <h2>Data-Driven Programming</h2> <p> |