From: Rob Pike
gofmt.
-Some formatting details remain. Very briefly, +Some formatting details remain. Very briefly:
if,
+ Go needs fewer parentheses than C and Java: control structures (if,
for, switch) do not have parentheses in
their syntax.
Also, the operator precedence hierarchy is shorter and clearer, so
x<<8 + y<<16- means what the spacing implies. + means what the spacing implies, unlike in the other languages.
/* */ block comments
and C++-style // line comments.
Line comments are the norm;
-block comments appear mostly as package comments and
-are also useful to disable large swaths of code.
+block comments appear mostly as package comments, but
+are useful within an expression or to disable large swaths of code.
@@ -205,6 +211,13 @@ takes care of that.
The comments are uninterpreted plain text, so HTML and other
annotations such as _this_ will reproduce verbatim and should
not be used.
+One adjustment godoc does do is to display indented
+text in a fixed-width font, suitable for program snippets.
+The package comment for the
+fmt package uses this to good effect.
+
Depending on the context, godoc might not even
reformat comments, so make sure they look good straight up:
use correct spelling, punctuation, and sentence structure,
@@ -231,6 +244,33 @@ starts with the name being declared.
func Compile(str string) (regexp *Regexp, err error) {
+
+If the name always begins the comment, the output of godoc
+can usefully be run through grep.
+Imagine you couldn't remember the name "Compile" but were looking for
+the parsing function for regular expressions, so you ran
+the command,
+
+$ godoc regexp | grep parse ++ +
+If all the doc comments in the package began, "This function...", grep
+wouldn't help you remember the name. But because the package starts each
+doc comment with the name, you'd see something like this,
+which recalls the word you're looking for.
+
+$ godoc regexp | grep parse + Compile parses a regular expression and returns, if successful, a Regexp + parsed. It simplifies safe initialization of global variables holding + cannot be parsed. It simplifies safe initialization of global variables +$ ++
Go's declaration syntax allows grouping of declarations. A single doc comment can introduce a group of related constants or variables. @@ -265,7 +305,7 @@ var (
Names are as important in Go as in any other language.
-In some cases they even have semantic effect: for instance,
+They even have semantic effect:
the visibility of a name outside a package is determined by whether its
first character is upper case.
It's therefore worth spending a little time talking about naming conventions
@@ -310,11 +350,11 @@ not encoding_base64 and not encodingBase64.
-The importer of a package will use the name to refer to its contents
-(the import . notation is intended mostly for tests and other
-unusual situations and should be avoided unless necessary),
+The importer of a package will use the name to refer to its contents.
so exported names in the package can use that fact
to avoid stutter.
+(Don't use the import . notation, which can simplify
+tests that must run outside the package they are testing, but should otherwise be avoided.)
For instance, the buffered reader type in the bufio package is called Reader,
not BufReader, because users see it as bufio.Reader,
which is a clear, concise name.
@@ -335,9 +375,7 @@ Another short example is once.Do;
once.Do(setup) reads well and would not be improved by
writing once.DoOrWaitUntilDone(setup).
Long names don't automatically make things more readable.
-If the name represents something intricate or subtle, it's usually better
-to write a helpful doc comment than to attempt to put all the information
-into the name.
+A helpful doc comment can often be more valuable than an extra long name.
-Like C, Go's formal grammar uses semicolons to terminate statements; -unlike C, those semicolons do not appear in the source. +Like C, Go's formal grammar uses semicolons to terminate statements, +but unlike in C, those semicolons do not appear in the source. Instead the lexer uses a simple rule to insert semicolons automatically as it scans, so the input text is mostly free of them.
@@ -431,7 +469,8 @@ statements on a line, should you write code that way.
-One caveat. You should never put the opening brace of a
+One consequence of the semicolon insertion rules
+is that you cannot put the opening brace of a
control structure (if, for, switch,
or select) on the next line. If you do, a semicolon
will be inserted before the brace, which could cause unwanted
@@ -540,7 +579,7 @@ codeUsing(f, d)
-
An aside: The last example in the previous section demonstrates a detail of how the @@ -577,7 +616,7 @@ if it has already been declared, provided:
v
-(if v is already declared in an outer scope, the declaration will create a new variable),v is already declared in an outer scope, the declaration will create a new variable §),
v, andif-else chain.
You'll see it used often.
++§ It's worth noting here that in Go the scope of function parameters and return values +is the same as the function body, even though they appear lexically outside the braces +that enclose the body. +
+@@ -634,7 +679,7 @@ If you only need the first item in the range (the key or index), drop the second
for key := range m {
- if expired(key) {
+ if key.expired() {
delete(m, key)
}
}
@@ -652,29 +697,30 @@ for _, value := range array {
For strings, the range does more work for you, breaking out individual
-Unicode characters by parsing the UTF-8.
+Unicode code points by parsing the UTF-8.
Erroneous encodings consume one byte and produce the
replacement rune U+FFFD. The loop
-for pos, char := range "æ¥æ¬èª" {
- fmt.Printf("character %c starts at byte position %d\n", char, pos)
+for pos, char := range "æ¥æ¬\x80èª" { // \x80 is an illegal UTF-8 encoding
+ fmt.Printf("character %#U starts at byte position %d\n", char, pos)
}
prints
-character æ¥ starts at byte position 0
-character æ¬ starts at byte position 3
-character èª starts at byte position 6
+character U+65E5 'æ¥' starts at byte position 0
+character U+672C 'æ¬' starts at byte position 3
+character U+FFFD '�' starts at byte position 6
+character U+8A9E 'èª' starts at byte position 7
Finally, Go has no comma operator and ++ and --
are statements not expressions.
Thus if you want to run multiple variables in a for
-you should use parallel assignment.
+you should use parallel assignment (although that precludes ++ and --).
// Reverse a
@@ -757,19 +803,23 @@ variable. Such a type switch uses the syntax of a type
assertion with the keyword type inside the parentheses.
If the switch declares a variable in the expression, the variable will
have the corresponding type in each clause.
+It's also idiomatic to reuse the name in such cases, in effect declaring
+a new variable with the same name but a different type in each case.
-switch t := interfaceValue.(type) {
+var t interface{}
+t = functionOfSomeType()
+switch t := t.(type) {
default:
- fmt.Printf("unexpected type %T", t) // %T prints type
+ fmt.Printf("unexpected type %T", t) // %T prints whatever type t has
case bool:
- fmt.Printf("boolean %t\n", t)
+ fmt.Printf("boolean %t\n", t) // t has type bool
case int:
- fmt.Printf("integer %d\n", t)
+ fmt.Printf("integer %d\n", t) // t has type int
case *bool:
- fmt.Printf("pointer to boolean %t\n", *t)
+ fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
- fmt.Printf("pointer to integer %d\n", *t)
+ fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}