go/doc/effective_go.html
Rob Pike 401c0b3b46 get this out of the way
OCL=33178
CL=33180
2009-08-13 11:29:05 -07:00

803 lines
21 KiB
HTML

<h2 id="introduction">Introduction</h2>
<p>
Go is a new language. Although it's in the C family of languages
it has some unusual properties that make effective Go programs
different in character from programs in C, C++, or Java.
To write Go well, it's important to understand its properties
and idioms.
</p>
<p>
This document gives tips for writing clear, idiomatic Go code
and points out common mistakes.
It augments the <a href="go_spec.html">language specification</a>
and the <a href="go_tutorial.html">tutorial</a>, both of which you
should read first.
</p>
<h3 id="read">Read good code</h3>
<p>
The first step in learning to write good code is to read good code.
The <a href="/src/pkg/">Go package sources</a>
are intended to serve not
only as the core library but also as examples of how to
use the language. Read them and follow their example.
</p>
<h2 id="formatting">Formatting</h2>
<p>
Formatting issues are the most contentious
but the least consequential.
People adapt to different formatting styles,
but they shouldn't be asked to.
Everyone
should use the same formatting; as in English,
consistent punctuation and spacing make the
text easier to read.
Most of the local formatting style can be
picked up by reading existing Go programs,
but to make them explicit here are some common points.
</p>
<h3 id="tabs">Use tabs</h3>
<p>
Use tabs, not spaces, for indentation.
</p>
<h3 id="columns">Don't worry about columnation</h3>
<p>
Let tools such as <code>gofmt</code> take care of lining things up.
</p>
<h3 id="white-space">Trim trailing white space</h3>
<p>
There should be no trailing white space at the end of lines.
</p>
<h3 id="line-wrapping">Don't wrap lines</h3>
<p>
Go has no 80-character limit. Don't bother with fancy line
wrapping just because a line is wider than a punched card.
If a line is too long, indent with an extra tab.
</p>
<h3 id="parens">Omit parentheses in control structures</h3>
<p>Go does not require parentheses around the expression
following the <code>for</code>, <code>if</code>, <code>range</code>,
<code>switch</code>, and <code>return</code> keywords.
</p>
<h3 id="line-comments">Use line comments</h3>
<p>
Go provides C-style <code>/* */</code> block comments
and C++-style <code>//</code> line comments.
Use line comments by default,
reserving block comments for top-level package comments
and commenting out large swaths of code.
</p>
<h3 id="pkg-comments">Write package comments</h3>
<p>
Every package should have a package comment, a block
comment preceding the package clause.
It should introduce the package and
provide information relevant to the package as a whole.
</p>
<pre>
/*
The regexp package implements a simple library for
regular expressions.
The syntax of the regular expressions accepted is:
regexp:
concatenation { '|' concatenation }
concatenation:
{ closure }
closure:
term [ '*' | '+' | '?' ]
term:
'^'
'$'
'.'
character
'[' [ '^' ] character-ranges ']'
'(' regexp ')'
*/
package regexp
</pre>
<p>
Consider how the package comment contributes to the appearance
of the <code>godoc</code> page for the package. Don't just
echo the doc comments for the components. The package comment
can be brief.
</p>
<pre>
// The path package implements utility routines for
// manipulating slash-separated filename paths.
</pre>
<h3 id="doc-comments">Write doc comments</h3>
<p>
If a comment immediately precedes a top-level declaration,
the <a href="/">Go documentation server</a>
<font color=red>(TODO: that's not a public URL.)</font>
uses that comment as the documentation
for the constant, function, method, package, type or variable being declared.
These are called <i>doc comments</i>.
To detach a comment from a declaration, insert a blank
line between them.
</p>
<p>
Every exported (capitalized) name in a program should
have a doc comment, as should the package declaration itself.
If a name appears multiple times due to forward declarations
or appearance in multiple source files within a package, only
one instance requires a doc comment, and any one will do.
</p>
<p>
Doc comments consist of complete English sentences.
The first sentence should be a one-sentence summary that
starts with the name being declared:
</p>
<pre>
// Quote returns a double-quoted Go string literal
// representing s. The returned string s uses Go escape
// sequences (\t, \n, \xFF, \u0100) for control characters
// and non-ASCII characters.
func Quote(s string) string {
</pre>
<p>
Use of complete English sentences admits
a wider variety of automated presentations.
</p>
<h3 id="ascii-art">Avoid ASCII Art</h3>
<p>
Go programs are meant to read equally well using
fixed-width and variable-width fonts.
Don't use fancy formattings that depend on fixed-width fonts.
In particular, don't assume that a single space is the same
width as every other character.
If you need to make a columnated table, use tabs to separate
the columns and the pretty printer will make
sure the columns are lined up properly in the output.
</p>
<p>
If you need comments to separate
sections in a file, use a simple block comment:
</p>
<pre>
/*
* Helper routines for simplifying the fetching of optional
* fields of basic type. If the field is missing, they return
* the zero for the type.
*/
</pre>
or
<pre>
/*
Helper routines for simplifying the fetching of optional
fields of basic type. If the field is missing, they return
the zero for the type.
*/
</pre>
<p>
Comments are text, not HTML; they contain no markup.
Refrain from ASCII embellishment like *this* or /this/.
</p>
<h3 id="groups">Use grouping to organize declarations</h3>
<p>
Go's declaration syntax allows grouping of declarations.
A comment can introduce a group of related constants or variables.
</p>
<pre>
// Flags to Open, wrapping those of the underlying system.
// Not all flags may be implemented on a given system.
const (
O_RDONLY = syscall.O_RDONLY; // Open file read-only.
O_WRONLY = syscall.O_WRONLY; // Open file write-only.
...
)
</pre>
<p>
A grouping can also indicate relationships between items,
such as the fact that a set of variables is controlled by
a mutex.
</p>
<pre>
// Variables protected by countLock.
var (
countLock sync.Mutex;
inputCount uint32;
outputCount uint32;
errorCount uint32;
)
</pre>
<h2 id="names">Names</h2>
<h3 id="mixed-caps">Use MixedCaps</h3>
<p>
Go uses the case of the first letter in a name to decide
whether the name is visible in other packages.
Multiword names use MixedCaps or mixedCaps
rather than underscores.
</p>
<h3 id="package-names">Use short package names</h3>
<p>
Package names are lower case single-word names:
there should be no need for underscore or mixedCaps.
The package name is conventionally the base name of
the source directory: the package in <code>src/pkg/container/vector</code>
is installed as <code>"container/vector"</code> but has name <code>vector</code>,
not <code>container_vector</code> and not <code>containerVector</code>.
The package name is only the default name used
when importing the package; it need not be unique
across all source code.
</p>
<h3 id="name-length">Avoid long names</h3>
<p>
A name's length should not exceed its information content.
For a function-local variable
in scope only for a few lines, the name <code>i</code> conveys just
as much information as <code>index</code> or <code>idx</code> and is easier to read.
Letters are easier to distinguish than numbers; use <code>i</code> and <code>j</code>
not <code>i1</code> and <code>i2</code>.
</p>
<p>
Exported names must convey more information
because they appear far from their origin.
Even so, longer names are not always better,
and the package name can help convey information:
the buffered <code>Reader</code> is <code>bufio.Reader</code>, not <code>bufio.BufReader</code>.
Similarly, <code>once.Do</code> is as precise and evocative as
<code>once.DoOrWaitUntilDone</code>, and <code>once.Do(f)</code> reads
better than <code>once.DoOrWaitUntilDone(f)</code>.
Encoding small essays into function names is not Go style;
clear names with good documentation is.
</p>
<h3 id="interfacers">Use the -er convention for interface names</h3>
<p>
One-method interfaces are conventionally named by
the method name plus the -er suffix: <code>Reader</code>,
<code>Writer</code>, <code>Formatter</code>.
</p>
<h3 id="common-names">Use canonical names</h3>
<p>
A few method names—<code>Read</code>, <code>Write</code>, <code>Close</code>, <code>Flush</code>, <code>String</code>—have
canonical signatures and meanings. To avoid confusion,
don't give your method one of those names unless it
has the same signature and meaning.
Conversely, if your type implements a method with the
same meaning as a method on a well-known type,
give it the same name and signature.
</p>
<p>
Some function-local variables have canonical names too.
Just as <code>i</code> is idiomatic in Go for an
index variable, <code>n</code> is idiomatic for a count, <code>b</code> for a <code>[]byte</code>,
<code>s</code> for a <code>string</code>, <code>r</code> for a <code>Reader</code>,
<code>err</code> for an <code>os.Error</code>
and so on.
Don't mix shorthands: it is especially confusing to
have two different variables <code>i</code> and <code>idx</code>,
or <code>n</code> and <code>cnt</code>.
</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 therefore 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();
// Prepare RPCMessage to send to server
rpc := &amp;RPCMessage {
Version: 1,
Header: &amp;RPCHeader {
Id: nextId(),
Signature: sign(body),
Method: method,
},
Body: body,
};
</pre>
<p>
Array, slice, and map literals behave similarly, although it is
unusual to need the address of a slice or map.
</p>
<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,
the body ends in <code>break</code>, <code>continue</code>,
<code>goto</code>, or <code>return</code>—omit the <code>else</code>.
</p>
<pre>
f, err := os.Open(name, os.O_RDONLY, 0);
if err != nil {
return err;
}
codeUsing(f);
</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 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>.
</p>
<a href="/src/pkg/http/url.go">go/src/pkg/http/url.go</a>:
<pre>
func unhex(c byte) byte {
switch {
case '0' &lt;= c &amp;&amp; c &lt;= '9':
return c - '0'
case 'a' &lt;= c &amp;&amp; c &lt;= 'f':
return c - 'a' + 10
case 'A' &lt;= c &amp;&amp; c &lt;= 'F':
return c - 'A' + 10
}
return 0
}
</pre>
<a href="/src/pkg/http/url.go">go/src/pkg/http/url.go</a>:
<pre>
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&amp;', '=', '#', '+', '%':
return true
}
return false
}
</pre>
<a href="/src/pkg/bytes/bytes.go">go/src/pkg/bytes/bytes.go</a>:
<pre>
// Compare returns an integer comparing the two byte arrays
// lexicographically.
// The result will be 0 if a==b, -1 if a &lt; b, and +1 if a &gt; b
func Compare(a, b []byte) int {
for i := 0; i &lt; len(a) &amp;&amp; i &lt; len(b); i++ {
switch {
case a[i] &gt; b[i]:
return 1
case a[i] &lt; b[i]:
return -1
}
}
switch {
case len(a) &lt; len(b):
return -1
case len(a) &gt; len(b):
return 1
}
return 0
}
</pre>
<h2 id="functions">Functions</h2>
<h3 id="omit-wrappers">Omit needless wrappers</h3>
<p>
Functions are great for factoring out common code, but
if a function is only called once,
ask whether it is necessary,
especially if it is just a short wrapper around another function.
This style is rampant in C++ code: wrappers
call wrappers that call wrappers that call wrappers.
This style hinders people trying to understand the program,
not to mention computers trying to execute it.
</p>
<h3 id="multiple-returns">Return multiple values</h3>
<p>
If a function must return multiple values, it can
do so directly.
There is no need to pass a pointer to a return value.
</p>
<h2 id="errors">Errors</h2>
<h3 id="error-returns">Return <code>os.Error</code>, not <code>bool</code></h3>
<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="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 jumps,
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
describe the error and provide context.
For example, <code>os.Open</code> returns an <code>os.PathError</code>:
<a href="/src/pkg/os/file.go">/src/pkg/os/file.go</a>:
<pre>
// PathError records an error and the operation and
// file path that caused it.
type PathError struct {
Op string;
Path string;
Error Error;
}
func (e *PathError) String() string {
return e.Op + &quot; &quot; + e.Path + &quot;: &quot; + 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
</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.
</p>
<p>
Callers that care about the precise error details can
use a type switch or a type guard 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.
</p>
<h2 id="types">Programmer-defined types</h2>
<h3 id="constructors">Use <code>NewTypeName</code> for constructors</h3>
<p>
The constructor for the type <code>pkg.MyType</code> should
be named <code>pkg.NewMyType</code> and should return <code>*pkg.MyType</code>.
The implementation of <code>NewTypeName</code> often uses the
<a href="#struct-allocation">struct allocation idiom</a>.
</p>
<a href="xxx">go/src/pkg/os/file.go</a>:
<pre>
func NewFile(fd int, name string) *File {
if file &lt; 0 {
return nil
}
return &amp;File{fd, name, nil, 0}
}
</pre>
<p>Packages that export only a single type sometimes
shorten <code>NewTypeName</code> to <code>New</code>;
the vector constructor is
<code>vector.New</code>, not <code>vector.NewVector</code>.
</p>
<p>
A type that is intended to be allocated
as part of a larger struct may have an <code>Init</code> method
that must be called explicitly.
Conventionally, the <code>Init</code> method returns
the object being initialized, to make the constructor trivial:
</p>
<a href="xxx">go/src/pkg/container/vector/vector.go</a>:
<pre>
func New(len int) *Vector {
return new(Vector).Init(len)
}
</pre>
<h3 id="zero-value">Make the zero value meaningful</h3>
<p>
In Go, newly allocated memory and newly declared variables are zeroed.
If a type is intended to be allocated without using a constructor
(for example, as part of a larger struct or declared as a local variable),
define the meaning of the zero value and arrange for that meaning
to be useful.
</p>
<p>
For example, <code>sync.Mutex</code> does not
have an explicit constructor or <code>Init</code> method.
Instead, the zero value for a <code>sync.Mutex</code>
is defined to be an unlocked mutex.
</p>
<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>
tables
</p>
<p>
XXX struct tags for marshalling.
template
eventually datafmt
</p>
<h2>Concurrency</h2>
<h3 id="share-memory">Share memory by communicating</h3>
<p>
Do not communicate by sharing memory;
instead, share memory by communicating.
</p>
<p>
XXX, more here.
</p>
<h2>Testing</h2>
<h3 id="no-abort">Run tests to completion</h3>
<p>
Tests should not stop early just because one case has misbehaved.
If at all possible, let tests continue, in order to characterize the
problem in more detail.
For example, it is more useful for a test to report that <code>isPrime</code>
gives the wrong answer for 2, 3, 5, and 7 (or for 2, 4, 8, and 16) than to report
that <code>isPrime</code> gives the wrong answer for 2 and therefore
no more tests were run.
</p>
<h3 id="good-errors">Print useful errors when tests fail</h3>
<p>
If a test fails, print a concise message explaining the context,
what happened, and what was expected.
Many testing environments encourage causing the
program to crash, but stack traces and core dumps
have low signal to noise ratios and require reconstructing
the situation from scratch.
The programmer who triggers the test failure may be someone
editing the code months later or even someone editing a different
package on which the code depends.
Time invested writing a good error message now pays off when
the test breaks later.
</p>
<h3 id="data-driven-tests">Use data-driven tests</h3>
<p>
Many tests reduce to running the same code multiple times,
with different input and expected output.
Instead of using cut and paste to write this code,
create a table of test cases and write a single test that
iterates over the table.
Once the table is written, you might find that it
serves well as input to multiple tests. For example,
a single table of encoded/decoded pairs can be
used by both <code>TestEncoder</code> and <code>TestDecoder</code>.
</p>
<p>
This data-driven style dominates in the Go package tests.
<br>
<!-- search for for.*range here -->
</p>
<h3 id="reflect.DeepEqual">Use reflect.DeepEqual to compare complex values</h3>
<p>
The <code>reflect.DeepEqual</code> function tests
whether two complex data structures have equal values.
If a function returns a complex data structure,
<code>reflect.DeepEqual</code> combined with table-driven testing
makes it easy to check that the return value is
exactly as expected.
</p>
<h2 id="be-consistent">Be consistent</h2>
<p>
Programmers often want their style to be distinctive,
writing loops backwards or using custom spacing and
naming conventions. Such idiosyncracies come at a
price, however: by making the code look different,
they make it harder to understand.
Consistency trumps personal
expression in programming.
</p>
<p>
If a program does the same thing twice,
it should do it the same way both times.
Conversely, if two different sections of a
program look different, the reader will
expect them to do different things.
</p>
<p>
Consider <code>for</code> loops.
Traditionally, a loop over <code>n</code>
elements begins:
</p>
<pre>
for i := 0; i &lt; n; i++ {
</pre>
<p>
Much of the time, the loop could run in the opposite order
and still be correct:
</p>
<pre>
for i := n-1; i &gt;= 0; i-- {
</pre>
<p>
The convention
is to count up unless to do so would be incorrect.
A loop that counts down implicitly says &ldquo;something
special is happening here.&rdquo;
A reader who finds a program in which some
loops count up and the rest count down
will spend time trying to understand why.
</p>
<p>
Loop direction is just one
programming decision that must be made
consistently; others include
formatting, naming variables and methods,
whether a type
has a constructor, what tests look like, and so on.
Why is this variable called <code>n</code> here and <code>cnt</code> there?
Why is the <code>Log</code> constructor <code>CreateLog</code> when
the <code>List</code> constructor is <code>NewList</code>?
Why is this data structure initialized using
a structure literal when that one
is initialized using individual assignments?
These questions distract from the important one:
what does the code do?
Moreover, internal consistency is important not only within a single file,
but also within the the surrounding source files.
When editing code, read the surrounding context
and try to mimic it as much as possible, even if it
disagrees with the rules here.
It should not be possible to tell which lines
you wrote or edited based on style alone.
Consistency about little things
lets readers concentrate on big ones.
</p>
</div>
</body>
</html>