summaryrefslogtreecommitdiff
path: root/doc/effective_go.html
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2009-10-12 21:18:23 -0700
committerRob Pike <r@golang.org>2009-10-12 21:18:23 -0700
commitd2228692b279827a61100bbf8350688fe230448a (patch)
treeb8334595427c260f151fb48e311a8bb643b9af3a /doc/effective_go.html
parent4700ded2824b11233e9feb60ae3c3dc6063982cb (diff)
downloadgo-git-d2228692b279827a61100bbf8350688fe230448a.tar.gz
type switches
errors R=rsc DELTA=150 (74 added, 34 deleted, 42 changed) OCL=35647 CL=35650
Diffstat (limited to 'doc/effective_go.html')
-rw-r--r--doc/effective_go.html170
1 files changed, 105 insertions, 65 deletions
diff --git a/doc/effective_go.html b/doc/effective_go.html
index ec40ce87ab..73b91ca80f 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 + &quot; &quot; + e.Path + &quot;: &quot; + 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 &amp;&amp; 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>