Commit d2228692 authored by Rob Pike's avatar Rob Pike

type switches

errors

R=rsc
DELTA=150  (74 added, 34 deleted, 42 changed)
OCL=35647
CL=35650
parent 4700ded2
......@@ -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>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment