Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
d2228692
Commit
d2228692
authored
Oct 12, 2009
by
Rob Pike
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
type switches
errors R=rsc DELTA=150 (74 added, 34 deleted, 42 changed) OCL=35647 CL=35650
parent
4700ded2
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
105 additions
and
65 deletions
+105
-65
doc/effective_go.html
doc/effective_go.html
+105
-65
No files found.
doc/effective_go.html
View file @
d2228692
...
...
@@ -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>
<h
2 id="errors">Errors</h2
>
<h
3 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
&
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>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment