From eaf6a344b7af5cb81fd6dbfe196371c16f4dad42 Mon Sep 17 00:00:00 2001
From: Rob Pike
-Go is a new programming language.
-It eliminates some of the pitfalls in languages
-like C++ and Java but introduces other ones.
-Many remain the same.
-This page gives tips for writing clear, idiomatic Go code
+This document gives tips for writing clear, idiomatic Go code
and points out common mistakes to avoid.
It augments the language specification
and the tutorial, both of which you
-should be familiar with.
+should read first.
-The first step to improving as a writer is to read.
-This step is as necessary for programming as it is for prose,
-and it is skipped as often by programmers as by writers.
+The first step towards learning to write good code is to read good code.
The Go package sources
are intended to serve not
only as the core library but also as examples of how to
-use the language. Read them.
+use the language. Read them and follow their example.
Consistency makes programs easy to read.
If a program says the same thing twice,
-it should say it the same way both times,
-so that the parallel structure is clear.
-Conversely, if two different sections of
+it should say it the same way both times.
+Conversely, if two different sections of a
program look different, the reader will
-expect them to be doing different things.
+expect them to do different things.
@@ -58,43 +51,42 @@ for i := n-1; i >= 0; i-- {
The convention in most languages (including Go)
-is to count up unless doing so would be incorrect.
-A loop that counts down implicitly says “there's
-a specific reason to count down here; this situation is special.”
-A reader who finds a program in which half the
-loops count up and the other half count down
+is to count up unless to do so would be incorrect.
+A loop that counts down implicitly says “something
+special is happening here.”
+A reader who finds a program in which some
+loops count up and the rest count down
will spend time trying to understand why.
-A programmer who inserts counting-down
-loops for variety wastes the reader's time.
+Don't run loops backwards unless it's necessary.
-Loop direction is hardly the only
+Loop direction is just one
programming decision which a programmer
-might want to use to be distinctive:
+may be tempted to be distinctive:
tabs or spaces, choice of variable names,
choice of method names, whether a type
has a constructor, what tests look like, and on and on.
As in the loop example, inconsistency
sows confusion, and wastes time.
-Why is this variable called n here and cnt here?
+Why is this variable called
-This document describes how to use Go effectively.
-Equally important, it describes how to use Go idiomatically,
-so that a Go programmer seeing your code for
+This document describes how to use Go effectively and idiomatically
+so that a programmer seeing your code for
the first time can focus on what it does
and not why it is inconsistent with typical Go practices.
Consistency trumps every item listed below.
@@ -102,14 +94,7 @@ 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.
-
-Internal consistency is important in a single file,
-but source files do not exist in isolation.
-Code must be consistent with the surrounding source file as well,
-or the same problems arise.
+you wrote or edited based on style alone.
Formatting issues are the most contentious
but the least consequential.
-People adapt quite well to different formatting styles,
-even if at first the styles “look weird.”
-The most important consideration is that if everyone
-uses the same formatting, then a reader picking up an
-unfamiliar piece of code can focus on what
-the code does instead of what it looks like.
-Most of the local formatting style can and should be
-picked up by reading existing Go programs (see above).
-The following are the most common issues
-that Google programmers run into.
+People adapt to different formatting styles,
+even if at first the styles “look weird,”
+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 (see above),
+but to make them explicit here are some common points.
-Files should not contain trailing white space at the end of lines.
-The script
Go has no 80-character limit. Don't bother with fancy line
wrapping just because a line is wider than a punched card.
-If you must wrap a line, indent with a single tab.
+If you must wrap a line, indent with an extra tab.
Go does not require parentheses around the expression
following the
Go provides C-style
If a comment immediately precedes a top-level declaration,
the Go documentation server
+(TODO: that's not a public URL.)
uses that comment as the documentation
-for the constant, function, package, type or variable being declared.
+for the constant, function, method, package, type or variable being declared.
+These are called doc comments.
To detach a comment from a declaration, insert a blank
line between them.
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.
@@ -198,16 +186,6 @@ starts with the name being declared:
func Quote(s string) string {
-
-instead of:
-
The complete English sentence form admits
a wider variety of automated presentations.
@@ -223,7 +201,7 @@ 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 (in progress) will make
+the columns and the pretty printer will make
sure the columns are lined up properly in the output.
-instead of:
-
-Comments are text, not HTML, and not any kind of markup.
+Comments are text, not HTML; they contain no markup.
Refrain from ASCII embellishment like *this* or /this/.
-As usual, read the Go sources for examples.
Go uses the case of the first letter in a name to decide
whether the name is visible in other packages.
-In Go, multiword names use MixedCaps or mixedCaps
+Multiword names use MixedCaps or mixedCaps
rather than underscores.
-Package names are lowercase single-word names:
+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
A name's length should not exceed its information content.
For a function-local variable
in scope only for a few lines, the name
-Exported names must convey more information,
-because they appear in a larger variety of contexts.
+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
One-method interfaces are conventionally named by
the method name plus the -er suffix: Introduction
Read
+Read good code
Be consistent
@@ -30,11 +24,10 @@ use the language. Read them.
n
here and cnt
there?
Why is the Log
constructor CreateLog
when
-the Vector
constructor is NewVector
?
+the List
constructor is NewList
?
Why is this data structure initialized using
-a structure literal when this other one
+a structure literal when that one
is initialized using individual assignments?
-Why is this idiom used here but not there?
-And on and on.
+And so on.
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.
Being consistent about little things
lets readers concentrate on big ones.
Formatting
@@ -117,16 +102,16 @@ or the same problems arise.
Use tabs
@@ -138,9 +123,7 @@ The local style is to use tabs, not spaces, for indentation.
Trim trailing white space
/home/rsc/bin/g4ws
removes trailing
-whitespace from all open files in the current g4 client.
+There should be no trailing white space at the end of lines.
Don't wrap lines mechanically
@@ -148,14 +131,14 @@ whitespace from all open files in the current g4 client.
Omit parentheses
+Omit parentheses in control structures
for
, if
, range
,
-and switch
keywords.
+switch
, and return
keywords.
Use line comments
@@ -163,7 +146,7 @@ and switch
keywords.
/* */
block comments
and C++-style //
line comments.
-The local style is to use line comments by default,
+Use line comments by default,
reserving block comments for top-level package comments
and commenting out large swaths of code.
-/* not Go style */
-// Return a double-quoted Go string literal representing s....
-func Quote(s string) string {
-
-
-/* not Go style */
-//////////////////////////////////////////////////////////////////////
-// Helper routines for simplifying the fetching of optional fields of basic type.
-// If the field is missing, they return the zero for the type.
+
+/*
+ Helper routines for simplifying the fetching of optional fields of basic type.
+ If the field is missing, they return the zero for the type.
+ */
Names
@@ -263,40 +238,38 @@ As usual, read the Go sources for examples.
Use short package names
src/pkg/container/vector
-is installed as "container/vector"
but has name vector,
+is installed as "container/vector"
but has name vector
,
not container_vector
and not containerVector
.
The package name is only the default name used
-when importing the package; it need not be a unique
-identifier.
+when importing the package; it need not be unique
+across all source code.
Avoid lengthy names
+Avoid long names
i
conveys just
as much information as index
or idx
and is easier to read.
-On the same note, i
and j
are better pair of names for
-index variables than i1
and i2
(or, worse, index1
and index2
),
-because they are easier to tell apart when reading
-the program quickly.
+Letters are easier to distinguish than numbers; use i
and j
+not i1
and i2
.
Reader
is bufio.Reader
, not bufio.BufReader
.
@@ -313,10 +286,7 @@ to use them without documentation.
Reader
,
-Writer
, Formatter
. Using an interface name distinct
-from the method name keeps an anonymous struct
-field of type Reader
from conflicting with its own
-Read
method.
+Writer
, Formatter
.
Use canonical names
@@ -328,7 +298,7 @@ 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, equally important, the same signature.
+give it the same name and signature.
@@ -370,11 +340,7 @@ hdr, body, checksum := buf[0:20], buf[20:len(buf)-4], buf[len(buf)-4:len(buf)];
If an if
body doesn't flow off the end of the
body—that is, the body ends in break
, continue
,
-goto
, or return
—it is preferable to omit the else
.
-
-For example:
+goto
, or return
—omit the else
.
@@ -383,40 +349,43 @@ if err != nil { return err; } codeUsing(f); -f.Close(); -moreCode();-
-is preferable to: - -
-/* not Go style */ -if f, err := os.Open(name, os.O_RDONLY, 0); err != nil { - return err; -} else { - codeUsing(f); - f.Close(); -} -moreCode(); -- -
-The first form
-avoids unnecessary indentation
-and makes it clear that moreCode()
-only runs when f.Close()
does.
-
-Go's switch
is more powerful than C's.
+Go's switch
is more general than C's.
When an if
-else if
-else
chain has three or more bodies,
or an if
condition has a long list of alternatives,
-consider rewriting it using switch
.
+it will be clearer if rewritten as a switch
.
+func unhex(c byte) byte { + switch { + case '0' <= c && c <= '9': + return c - '0' + case 'a' <= c && c <= 'f': + return c - 'a' + 10 + case 'A' <= c && c <= 'F': + return c - 'A' + 10 + } + return 0 +} ++ +go/src/pkg/http/url.go: +
+func shouldEscape(c byte) bool { + switch c { + case ' ', '?', '&', '=', '#', '+', '%': + return true + } + return false +} ++ go/src/pkg/bytes/bytes.go:
// Compare returns an integer comparing the two byte arrays lexicographically. @@ -440,44 +409,18 @@ func Compare(a, b []byte) int { }-go/src/pkg/http/url.go: -
-func unhex(c byte) byte { - switch { - case '0' <= c && c <= '9': - return c - '0' - case 'a' <= c && c <= 'f': - return c - 'a' + 10 - case 'A' <= c && c <= 'F': - return c - 'A' + 10 - } - return 0 -} -- -go/src/pkg/http/url.go: -
-func shouldEscape(c byte) bool { - switch c { - case ' ', '?', '&', '=', '#', '+', '%': - return true - } - return false -} --
-Functions are great for factoring out common functionality. -If a function is only called once, -ask whether the function is really necessary, +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 runs rampant in C++ code: wrappers +This style is rampant in C++ code: wrappers call wrappers that call wrappers that call wrappers. -Doing this hinders people trying to understand the program, +This style hinders people trying to understand the program, not to mention computers trying to execute it.
@@ -486,17 +429,15 @@ not to mention computers trying to execute it.If a function must return multiple values, it can do so directly. -The C “pass in a pointer to a return value” -idiom is dead. +There is no need to pass a pointer to a return value.
--Errors tend to be simpler than non-error cases, +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, @@ -504,27 +445,17 @@ so that there is no need for an explicit else.
+if len(name) == 0 { + return; +} +if IsDir(name) { + return; +} f, err := os.Open(name, os.O_RDONLY, 0); if err != nil { - return err; + return; } codeUsing(f); -f.Close(); -moreCode(); -- -is preferable to: - -
-/* not Go style */ -f, err := os.Open(name, os.O_RDONLY, 0); -if err == nil { - codeUsing(f); - f.Close(); -} else { - return err; -} -moreCode();
os.Error
, not bool
Packages that export only a single type sometimes
shorten NewTypeName
to New
;
-for example, the vector constructor is
+the vector constructor is
vector.New
, not vector.NewVector
.
crc32.NewIEEE()
and adler32.New()
return type hash.Hash32
.
Substituting the CRC-32 algorithm for Adler-32 in a Go program
requires only changing the constructor call:
-the rest of the code cannot distinguish the two algorithms.
+the rest of the code is unaffected by the change of algorithm.
-