From 9e2fbe186d9bf0fabd96df5698824690a065db75 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 9 Mar 2011 16:47:40 -0800 Subject: [PATCH] Effective Go: some small cleanups. Add discussion of getters. Add example using a map as a set. R=golang-dev, gri, adg, iant CC=golang-dev https://golang.org/cl/4240100 --- doc/effective_go.html | 81 ++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/doc/effective_go.html b/doc/effective_go.html index a32179298e8..27bfd1bf52c 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -59,13 +59,14 @@ prescriptive style guide. With Go we take an unusual approach and let the machine take care of most formatting issues. -A program, gofmt, reads a Go program +The gofmt tool reads a Go program and emits the source in a standard style of indentation and vertical alignment, retaining and if necessary reformatting comments. If you want to know how to handle some new layout situation, run gofmt; if the answer doesn't -seem right, fix the program (or file a bug), don't work around it. +seem right, rearrange your program (or file a bug about gofmt), +don't work around it.

@@ -94,7 +95,7 @@ type T struct {

-All code in the libraries has been formatted with gofmt. +All Go code in the standard packages has been formatted with gofmt.

@@ -304,7 +305,8 @@ not container_vector and not containerVector.

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), so exported names in the package can use that fact +unusual situations and should be avoided unless necessary), +so exported names in the package can use that fact to avoid stutter. For instance, the buffered reader type in the bufio package is called Reader, not BufReader, because users see it as bufio.Reader, @@ -316,8 +318,8 @@ Similarly, the function to make new instances of ring.Ring—wh is the definition of a constructor in Go—would normally be called NewRing, but since Ring is the only type exported by the package, and since the -package is called ring, it's called just New. -Clients of the package see that as ring.New. +package is called ring, it's called just New, +which clients of the package see as ring.New. Use the package structure to help you choose good names.

@@ -331,6 +333,27 @@ to write a helpful doc comment than to attempt to put all the information into the name.

+

Getters

+ +

+Go doesn't provide automatic support for getters and setters. +There's nothing wrong with providing getters and setters yourself, +and it's often appropriate to do so, but it's neither idiomatic nor necessary +to put Get into the getter's name. If you have a field called +owner (lower case, unexported), the getter method should be +called Owner (upper case, exported), not GetOwner. +The use of upper-case names for export provides the hook to discriminate +the field from the method. +A setter function, if needed, will likely be called SetOwner. +Both names read well in practice: +

+
+owner := obj.Owner()
+if owner != user {
+	obj.SetOwner(user)
+}
+
+

Interface names

@@ -489,8 +512,8 @@ codeUsing(f)

-This is a example of a common situation where code must analyze a -sequence of error possibilities. The code reads well if the +This is an example of a common situation where code must guard against a +sequence of error conditions. 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 return statements, the resulting code needs no else statements. @@ -553,8 +576,9 @@ for _, value := range m { // key is unused

For strings, the range does more work for you, breaking out individual -Unicode characters by parsing the UTF-8 (erroneous encodings consume one byte and produce the -replacement rune U+FFFD). The loop +Unicode characters by parsing the UTF-8. +Erroneous encodings consume one byte and produce the +replacement rune U+FFFD. The loop

 for pos, char := range "日本語" {
@@ -571,8 +595,9 @@ character 語 starts at byte position 6
 

-Finally, since Go has no comma operator and ++ and -- -are statements not expressions, if you want to run multiple variables in a for +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.

@@ -676,7 +701,7 @@ case *int:
 
 

One of Go's unusual features is that functions and methods -can return multiple values. This can be used to +can return multiple values. This form can be used to improve on a couple of clumsy idioms in C programs: in-band error returns (such as -1 for EOF) and modifying an argument. @@ -811,7 +836,7 @@ func Contents(filename string) (string, os.Error) {

-Deferring a function like this has two advantages. First, it +Deferring a call to a function such as Close has two advantages. First, it guarantees that you will never forget to close the file, a mistake that's easy to make if you later edit the function to add a new return path. Second, it means that the close sits near the open, @@ -903,8 +928,9 @@ leaving: b For programmers accustomed to block-level resource management from other languages, defer may seem peculiar, but its most interesting and powerful applications come precisely from the fact -that it's not block-based but function based. In the section on -panic and recover we'll see an example. +that it's not block-based but function-based. In the section on +panic and recover we'll see another +example of its possibilities.

Data

@@ -949,7 +975,7 @@ type SyncedBuffer struct {

Values of type SyncedBuffer are also ready to use immediately upon allocation -or just declaration. In this snippet, both p and v will work +or just declaration. In the next snippet, both p and v will work correctly without further arrangement.

@@ -987,7 +1013,6 @@ an expression that creates a new instance each time it is evaluated.

-
 func NewFile(fd int, name string) *File {
     if fd < 0 {
@@ -999,7 +1024,7 @@ func NewFile(fd int, name string) *File {
 

-Note that it's perfectly OK to return the address of a local variable; +Note that, unlike in C, it's perfectly OK to return the address of a local variable; the storage associated with the variable survives after the function returns. In fact, taking the address of a composite literal @@ -1053,7 +1078,7 @@ is that these three types are, under the covers, references to data structures t must be initialized before use. A slice, for example, is a three-item descriptor containing a pointer to the data (inside an array), the length, and the -capacity; until those items are initialized, the slice is nil. +capacity, and until those items are initialized, the slice is nil. For slices, maps, and channels, make initializes the internal data structure and prepares the value for use. @@ -1273,7 +1298,21 @@ is not present in the map will return the zero value for the type of the entries in the map. For instance, if the map contains integers, looking up a non-existent key will return 0. +A set can be implemented as a map with value type bool. +Set the map entry to true to put the value in the set, and then +test it by simple indexing.

+
+attended := map[string] bool {
+    "Ann": true,
+    "Joe": true,
+    ...
+}
+
+if attended[person] { // will be false if person is not in the map
+    fmt.Println(person, "was at the meeting")
+}
+

Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" @@ -1298,7 +1337,7 @@ func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } - log.Println("unknown time zone", tz) + log.Println("unknown time zone:", tz) return 0 }