mirror of
https://github.com/golang/go
synced 2024-11-22 00:04:41 -07:00
semicolons, ifs, switches
R=rsc DELTA=196 (118 added, 24 deleted, 54 changed) OCL=33716 CL=33727
This commit is contained in:
parent
d55370760f
commit
c409976b85
@ -349,50 +349,106 @@ or <code>mixedCaps</code> rather than underscores to write
|
||||
multiword names.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="idioms">Idioms</h2>
|
||||
|
||||
<h3 id="struct-allocation">Allocate using literals</h3>
|
||||
<h2 id="semicolons">Semicolons</h2>
|
||||
|
||||
<p>
|
||||
A struct literal is an expression that creates a
|
||||
new instance each time it is evaluated. The address of such
|
||||
an expression points to a fresh instance each time.
|
||||
Use such expressions to avoid the repetition of filling
|
||||
out a data structure.
|
||||
Go needs fewer semicolons between statements than do other C variants.
|
||||
Semicolons are never required at the top level.
|
||||
Also they are separators, not terminators, so they
|
||||
can be left off the last element of a statement or declaration list,
|
||||
a convenience
|
||||
for one-line <code>funcs</code> and the like:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
length := Point{x, y}.Abs();
|
||||
func CopyInBackground(src, dst chan Item) {
|
||||
go func() { for { dst <- <-src } }()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
// Prepare RPCMessage to send to server
|
||||
rpc := &RPCMessage {
|
||||
Version: 1,
|
||||
Header: &RPCHeader {
|
||||
Id: nextId(),
|
||||
Signature: sign(body),
|
||||
Method: method,
|
||||
},
|
||||
Body: body,
|
||||
};
|
||||
</pre>
|
||||
|
||||
<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="control-flow">Control Flow</h2>
|
||||
|
||||
<h3 id="else">Omit needless else bodies</h3>
|
||||
|
||||
<p>
|
||||
When an <code>if</code> statement doesn't flow into the next statement—that is,
|
||||
In fact, semicolons can omitted at the end of any "StatementList" in the
|
||||
grammar, which includes things like cases in <code>switch</code>
|
||||
statements:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
switch {
|
||||
case a < b:
|
||||
return -1
|
||||
case a == b:
|
||||
return 0
|
||||
case a > b:
|
||||
return 1
|
||||
}
|
||||
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The grammar admits an empty statement after any statement list, which
|
||||
means a terminal semicolon is always OK. As a result,
|
||||
it's fine to put semicolons everywhere you'd put them in a
|
||||
C program—they would be fine after those return statements,
|
||||
for instance—but they can often be omitted.
|
||||
By convention, they're always left off top-level declarations (for
|
||||
instance, they don't appear after the closing brace of <code>struct</code>
|
||||
declarations, or of <code>funcs</code> for that matter)
|
||||
and often left off one-liners. But within functions, place them
|
||||
as you see fit.
|
||||
</p>
|
||||
|
||||
<h2 id="control-structures">Control structures</h2>
|
||||
|
||||
<p>
|
||||
The control structures of Go are related to those of C but different
|
||||
in important ways.
|
||||
There is no <code>do</code> or <code>while</code> loop, only a
|
||||
slightly generalized
|
||||
<code>for</code>;
|
||||
<code>switch</code> is more flexible;
|
||||
<code>if</code> and <code>switch</code> accept an optional
|
||||
initialization statement like that of <code>for</code>;
|
||||
and there are new control structures including a type switch and a
|
||||
multiway communications multiplexer, <code>select</code>.
|
||||
The syntax is also slightly different: parentheses are not part of the syntax
|
||||
and the bodies must always be brace-delimited.
|
||||
</p>
|
||||
|
||||
<h3 id="if">If</h3>
|
||||
|
||||
<p>
|
||||
In Go a simple <code>if</code> looks like this:
|
||||
</p>
|
||||
<pre>
|
||||
if x > 0 {
|
||||
return y
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Mandatory braces encourage writing simple <code>if</code> statements
|
||||
on multiple lines. It's good style to do so anyway,
|
||||
especially when the body contains a control statement such as a
|
||||
<code>return</code> or <code>break</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Since <code>if</code> and <code>switch</code> accept an initialization
|
||||
statement, it's common to see one used to set up a local variable:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
if err := file.Chmod(0664); err != nil {
|
||||
log.Stderr(err)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p id="else">
|
||||
In the Go libraries, you'll find that
|
||||
when an <code>if</code> statement doesn't flow into the next statement—that is,
|
||||
the body ends in <code>break</code>, <code>continue</code>,
|
||||
<code>goto</code>, or <code>return</code>—omit the <code>else</code>.
|
||||
<code>goto</code>, or <code>return</code>—the unnecessary
|
||||
<code>else</code> is omitted.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@ -403,17 +459,40 @@ if err != nil {
|
||||
codeUsing(f);
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This is a example of a common situation where code must analyze a
|
||||
sequence of error possibilities. The code reads well if the
|
||||
successful flow of control runs down the page, eliminating error cases
|
||||
as they arise. Since error cases tend to end in <code>return</code>
|
||||
statements, the resulting code needs no <code>else</code> statements:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
f, err := os.Open(name, os.O_RDONLY, 0);
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
d, err := f.Stat();
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
codeUsing(f, d);
|
||||
</pre>
|
||||
|
||||
|
||||
<h3 id="switch">Switch</h3>
|
||||
|
||||
<p>
|
||||
Go's <code>switch</code> is more general than C's.
|
||||
When an <code>if</code>-<code>else</code>-<code>if</code>-<code>else</code>
|
||||
chain has three or more bodies,
|
||||
or an <code>if</code> condition has a long list of alternatives,
|
||||
it will be clearer if rewritten as a <code>switch</code>.
|
||||
The expressions need not be constants or even integers,
|
||||
the cases are evaluated top to bottom until a match is found,
|
||||
and if the <code>switch</code> has no expression it switches on
|
||||
<code>true</code>.
|
||||
It's therefore possible—and idiomatic—to write an
|
||||
<code>if</code>-<code>else</code>-<code>if</code>-<code>else</code>
|
||||
chain as a <code>switch</code>:
|
||||
</p>
|
||||
|
||||
<a href="/src/pkg/http/url.go">go/src/pkg/http/url.go</a>:
|
||||
<pre>
|
||||
func unhex(c byte) byte {
|
||||
switch {
|
||||
@ -428,7 +507,9 @@ func unhex(c byte) byte {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<a href="/src/pkg/http/url.go">go/src/pkg/http/url.go</a>:
|
||||
<p>
|
||||
There is no automatic fall through, but cases can be presented
|
||||
in comma-separated lists:
|
||||
<pre>
|
||||
func shouldEscape(c byte) bool {
|
||||
switch c {
|
||||
@ -439,7 +520,9 @@ func shouldEscape(c byte) bool {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<a href="/src/pkg/bytes/bytes.go">go/src/pkg/bytes/bytes.go</a>:
|
||||
<p>
|
||||
Here's a comparison routine for byte arrays that uses two
|
||||
<code>switch</code> statements:
|
||||
<pre>
|
||||
// Compare returns an integer comparing the two byte arrays
|
||||
// lexicographically.
|
||||
@ -486,6 +569,41 @@ do so directly.
|
||||
There is no need to pass a pointer to a return value.
|
||||
</p>
|
||||
|
||||
<h2 id="idioms">Idioms</h2>
|
||||
|
||||
<h3 id="struct-allocation">Allocate using literals</h3>
|
||||
|
||||
<p>
|
||||
A struct literal is an expression that creates a
|
||||
new instance each time it is evaluated. The address of such
|
||||
an expression points to a fresh instance each time.
|
||||
Use such expressions to avoid the repetition of filling
|
||||
out a data structure.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
length := Point{x, y}.Abs();
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
// Prepare RPCMessage to send to server
|
||||
rpc := &RPCMessage {
|
||||
Version: 1,
|
||||
Header: &RPCHeader {
|
||||
Id: nextId(),
|
||||
Signature: sign(body),
|
||||
Method: method,
|
||||
},
|
||||
Body: body,
|
||||
};
|
||||
</pre>
|
||||
|
||||
<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="errors">Errors</h2>
|
||||
|
||||
<h3 id="error-returns">Return <code>os.Error</code>, not <code>bool</code></h3>
|
||||
@ -498,30 +616,6 @@ Even if there is only one failure mode now,
|
||||
there may be more later.
|
||||
</p>
|
||||
|
||||
<h3 id="handle-errors-first">Handle errors first</h3>
|
||||
|
||||
<p>
|
||||
Error cases tend to be simpler than non-error cases,
|
||||
and it helps readability when the non-error flow
|
||||
of control is always down the page.
|
||||
Also, error cases tend to end in <code>return</code> statements,
|
||||
so that there is <a href="#else">no need for an explicit else</a>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
if len(name) == 0 {
|
||||
return os.EINVAL;
|
||||
}
|
||||
if IsDir(name) {
|
||||
return os.EISDIR;
|
||||
}
|
||||
f, err := os.Open(name, os.O_RDONLY, 0);
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
codeUsing(f);
|
||||
</pre>
|
||||
|
||||
<h3 id="error-context">Return structured errors</h3>
|
||||
|
||||
Implementations of <code>os.Error</code> should
|
||||
|
Loading…
Reference in New Issue
Block a user