]> Cypherpunks repositories - gostls13.git/commitdiff
doc/effective_go.html: add a section about the blank identifier
authorRuss Cox <rsc@golang.org>
Tue, 22 Jan 2013 19:00:10 +0000 (14:00 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 22 Jan 2013 19:00:10 +0000 (14:00 -0500)
R=golang-dev, minux.ma, bradfitz, adg
CC=golang-dev
https://golang.org/cl/7134056

doc/effective_go.html
doc/progs/unused1.go [new file with mode: 0644]
doc/progs/unused2.go [new file with mode: 0644]

index f7b07b02e3c2a27bdf1658f9adf08f7207bd0589..1363f092f1f9d471814baf2fad7dda69f05f02ca 100644 (file)
@@ -2966,6 +2966,156 @@ filter unexpected problems and re-panic with the original error.
 That's left as an exercise for the reader.
 </p>
 
+<h2 id="blank">Blank identifier</h2>
+
+<p>
+Go defines a special identifier <code>_</code>, called the <i>blank identifier</i>.
+The blank identifier can be used in a declaration to avoid
+declaring a name, and it can be used in an assignment to discard a value.
+This definition makes it useful in a variety of contexts.
+</p>
+
+<h3 id="blank_assign">Multiple assignment</h3>
+
+<p>
+If an assignment requires multiple values on the left side,
+but one of the values will not be used by the program,
+using the blank identifier in the assignment avoids the need
+to create a dummy variable.
+We saw one example of this in the discussion of
+<a href="#for">for loops</a> above.
+</p>
+<pre>
+sum := 0
+for _, value := range array {
+    sum += value
+}
+</pre>
+
+<p>
+Another common use is when calling a function that returns
+a value and an error, but only the error is important.
+</p>
+<pre>
+if _, err := os.Stat(path); os.IsNotExist(err) {
+       fmt.Printf("%s does not exist\n", path)
+}
+</pre>
+
+<p>
+A final use that is more common than it should be is to 
+discard the error from a function that is not expected to fail.
+This is usually a mistake: when the function does fail, the code
+will continue on and probably panic dereferencing a nil pointer.
+</p>
+<pre>
+// Always check errors: this program crashes if path does not exist.
+fi, _ := os.Stat(path)
+fmt.Printf("%s is %d bytes\n", path, fi.Size())
+</pre>
+
+<h3 id="blank_unused">Unused imports and variables</h3>
+
+<p>
+Go defines that it is an error to import a package without using it,
+or to declare a variable without using its value.
+Unused imports bloat a program and lengthen compiles unnecessarily;
+a variable that is initialized but not used is at least
+a wasted computation and perhaps indicative of a
+larger bug.
+Of course, both of these situations also arise in programs
+that are under active development, as you test and refine
+your code. 
+</p>
+<p>
+For example, in this program, there are two unused imports
+(<code>fmt</code> and <code>io</code>)
+and an unused variable (<code>greeting</code>).
+</p>
+{{code "/doc/progs/unused1.go" `/package/` `$`}}
+<p>
+Top-level blank declarations referring to the packages
+will silence the unused import errors.
+By convention, these declarations should come immediately after
+the imports, as a reminder to clean things up later.
+Similarly, assigning <code>greeting</code> to a blank identifier
+will silence the unused variable error.
+</p>
+{{code "/doc/progs/unused2.go" `/package/` `$`}}
+<p>
+
+<h3 id="blank_import">Import for side effect</h3>
+
+<p>
+An unused import like <code>fmt</code> or <code>io</code> in the last section
+should eventually be used or removed:
+blank assignments identify code as a work in progress.
+But sometimes it is useful to import a package only for its
+side effects, without any explicit use.
+For example, during its <code>init</code> function,
+the <code><a href="/pkg/net/http/pprof/">net/http/pprof</a></code>
+package registers HTTP handlers that provide useful
+debugging information. It has an exported API too, but
+most clients need only the handler registration.
+In this situation, it is conventional to rename the package
+to the blank identifier:
+</p>
+<pre>
+import _ "net/http/pprof"
+</pre>
+<p>
+This form of import makes clear that the package is being
+imported for its side effects, because there is no other possible
+use of the package: in this file, it doesn't have a name.
+</p>
+
+<h3 id="blank_implements">Interface checks</h3>
+
+<p>
+As we saw in the discussion of <a href="#interfaces_and_types">interfaces</a> above,
+Go does not require a type to declare explicitly that it implements an interface.
+It implements the interface by simply implementing the required methods.
+This makes Go programs more lightweight and flexible, and it can avoid
+unnecessary dependencies between packages. 
+Most interface conversions are static, visible to the compiler,
+and therefore checked at compile time.
+For example, passing an <code>*os.File</code> to a function
+expecting an <code>io.Reader</code> will not compile unless
+<code>*os.File</code> implements the <code>io.Reader</code> interface.
+</p>
+<p>
+However, some types that are used only to satisfy dynamic interface checks.
+For example, the <code><a href="/pkg/encoding/json/">encoding/json</a></code>
+package defines a <code><a href="/pkg/encoding/json/#Marshaler">Marshaler</a></code>
+interface. If the JSON encoder encounters a type implementing that interface,
+the encoder will let the type convert itself to JSON instead of using the standard
+conversion.
+This check is done only at runtime, with code like:
+</p>
+<pre>
+m, ok := val.(json.Marshaler)
+</pre>
+<p>
+If a type—for example,
+<code><a href="/pkg/encoding/json/#RawMessage">json.RawMessage</a></code>—intends
+to customize its JSON representation, it should implement
+<code>json.Marshaler</code>, but there are no static conversions that would
+cause the compiler to verify this automatically.
+A declaration can be used to add such a check:
+</p>
+<pre>
+var _ json.Marshaler = (*MyMessage)(nil)
+</pre>
+<p>
+As part of type-checking this static assignment of a
+<code>*RawMessage</code> to a <code>Marshaler</code>,
+the Go compiler will require that <code>*RawMessage</code> implements <code>Marshaler</code>.
+Using the blank identifier here indicates that
+the declaration exists only for the type checking,
+not to create a variable.
+Conventionally, such declarations are used only when there are
+no static conversions already present in the code.
+</p>
 
 <h2 id="web_server">A web server</h2>
 
diff --git a/doc/progs/unused1.go b/doc/progs/unused1.go
new file mode 100644 (file)
index 0000000..96a6d98
--- /dev/null
@@ -0,0 +1,12 @@
+// skip
+
+package main
+
+import (
+       "fmt"
+       "io"
+)
+
+func main() {
+       greeting := "hello, world"
+}
diff --git a/doc/progs/unused2.go b/doc/progs/unused2.go
new file mode 100644 (file)
index 0000000..5c5f9d7
--- /dev/null
@@ -0,0 +1,16 @@
+// compile
+
+package main
+
+import (
+       "fmt"
+       "io"
+)
+
+var _ = fmt.Printf
+var _ io.Reader
+
+func main() {
+       greeting := "hello, world"
+       _ = greeting
+}