mirror of
https://github.com/golang/go
synced 2024-11-24 00:00:23 -07:00
cmd/godoc: add support for serving templates
doc: convert to use godoc built-in templates tmpltohtml is gone, to avoid having a second copy of the code. Instead, godoc -url /doc/go1.html will print the actual HTML served for that URL. "make" will generate files named go1.rawhtml etc, which can be fed through tidy. It can be hard to tell from the codereview diffs, but all the tmpl files have been renamed to be html files and then have "Template": true added. R=golang-dev, adg, r, gri CC=golang-dev https://golang.org/cl/5782046
This commit is contained in:
parent
e38c5fb23d
commit
a40065ac68
25
doc/Makefile
25
doc/Makefile
@ -2,21 +2,18 @@
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
HTML=\
|
||||
articles/defer_panic_recover.html\
|
||||
articles/error_handling.html\
|
||||
articles/slices_usage_and_internals.html\
|
||||
articles/laws_of_reflection.html\
|
||||
effective_go.html\
|
||||
go1.html\
|
||||
RAWHTML=\
|
||||
articles/defer_panic_recover.rawhtml\
|
||||
articles/error_handling.rawhtml\
|
||||
articles/slices_usage_and_internals.rawhtml\
|
||||
articles/laws_of_reflection.rawhtml\
|
||||
effective_go.rawhtml\
|
||||
go1.rawhtml\
|
||||
|
||||
all: tmpltohtml $(HTML)
|
||||
all: $(RAWHTML)
|
||||
|
||||
tmpltohtml: tmpltohtml.go
|
||||
go build tmpltohtml.go
|
||||
|
||||
%.html: %.tmpl tmpltohtml
|
||||
./tmpltohtml $*.tmpl > $@
|
||||
%.rawhtml: %.html
|
||||
godoc -url /doc/$* >$@
|
||||
|
||||
clean:
|
||||
rm -f $(HTML) tmpltohtml
|
||||
rm -f $(RAWHTML)
|
||||
|
@ -1,10 +1,7 @@
|
||||
<!--{
|
||||
"Title": "Defer, Panic, and Recover"
|
||||
"Title": "Defer, Panic, and Recover",
|
||||
"Template": true
|
||||
}-->
|
||||
<!--
|
||||
DO NOT EDIT: created by
|
||||
tmpltohtml articles/defer_panic_recover.tmpl
|
||||
-->
|
||||
|
||||
<p>
|
||||
Go has the usual mechanisms for control flow: if, for, switch, goto. It also
|
||||
@ -23,23 +20,7 @@ For example, let's look at a function that opens two files and copies the
|
||||
contents of one file to the other:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/defer.go" `/func CopyFile/` `/STOP/`}}
|
||||
-->func CopyFile(dstName, srcName string) (written int64, err error) {
|
||||
src, err := os.Open(srcName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
dst, err := os.Create(dstName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
written, err = io.Copy(dst, src)
|
||||
dst.Close()
|
||||
src.Close()
|
||||
return
|
||||
}</pre>
|
||||
{{code "/doc/progs/defer.go" `/func CopyFile/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This works, but there is a bug. If the call to os.Create fails, the
|
||||
@ -50,22 +31,7 @@ noticed and resolved. By introducing defer statements we can ensure that the
|
||||
files are always closed:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/defer2.go" `/func CopyFile/` `/STOP/`}}
|
||||
-->func CopyFile(dstName, srcName string) (written int64, err error) {
|
||||
src, err := os.Open(srcName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
dst, err := os.Create(dstName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer dst.Close()
|
||||
|
||||
return io.Copy(dst, src)
|
||||
}</pre>
|
||||
{{code "/doc/progs/defer2.go" `/func CopyFile/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Defer statements allow us to think about closing each file right after opening
|
||||
@ -88,13 +54,7 @@ In this example, the expression "i" is evaluated when the Println call is
|
||||
deferred. The deferred call will print "0" after the function returns.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/defer.go" `/func a/` `/STOP/`}}
|
||||
-->func a() {
|
||||
i := 0
|
||||
defer fmt.Println(i)
|
||||
i++
|
||||
return
|
||||
}</pre>
|
||||
{{code "/doc/progs/defer.go" `/func a/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
2. <i>Deferred function calls are executed in Last In First Out order
|
||||
@ -105,12 +65,7 @@ deferred. The deferred call will print "0" after the function returns.
|
||||
This function prints "3210":
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/defer.go" `/func b/` `/STOP/`}}
|
||||
-->func b() {
|
||||
for i := 0; i < 4; i++ {
|
||||
defer fmt.Print(i)
|
||||
}
|
||||
}</pre>
|
||||
{{code "/doc/progs/defer.go" `/func b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
3. <i>Deferred functions may read and assign to the returning function's named
|
||||
@ -122,11 +77,7 @@ In this example, a deferred function increments the return value i <i>after</i>
|
||||
the surrounding function returns. Thus, this function returns 2:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/defer.go" `/func c/` `/STOP/`}}
|
||||
-->func c() (i int) {
|
||||
defer func() { i++ }()
|
||||
return 1
|
||||
}</pre>
|
||||
{{code "/doc/progs/defer.go" `/func c/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This is convenient for modifying the error return value of a function; we will
|
||||
@ -156,36 +107,7 @@ to panic and resume normal execution.
|
||||
Here's an example program that demonstrates the mechanics of panic and defer:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/defer2.go" `/package main/` `/STOP/`}}
|
||||
-->package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
f()
|
||||
fmt.Println("Returned normally from f.")
|
||||
}
|
||||
|
||||
func f() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Recovered in f", r)
|
||||
}
|
||||
}()
|
||||
fmt.Println("Calling g.")
|
||||
g(0)
|
||||
fmt.Println("Returned normally from g.")
|
||||
}
|
||||
|
||||
func g(i int) {
|
||||
if i > 3 {
|
||||
fmt.Println("Panicking!")
|
||||
panic(fmt.Sprintf("%v", i))
|
||||
}
|
||||
defer fmt.Println("Defer in g", i)
|
||||
fmt.Println("Printing in g", i)
|
||||
g(i + 1)
|
||||
}</pre>
|
||||
{{code "/doc/progs/defer2.go" `/package main/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The function g takes the int i, and panics if i is greater than 3, or else it
|
||||
|
@ -1,195 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Defer, Panic, and Recover"
|
||||
}-->
|
||||
{{donotedit}}
|
||||
<p>
|
||||
Go has the usual mechanisms for control flow: if, for, switch, goto. It also
|
||||
has the go statement to run code in a separate goroutine. Here I'd like to
|
||||
discuss some of the less common ones: defer, panic, and recover.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A <b>defer statement</b> pushes a function call onto a list. The list of saved
|
||||
calls is executed after the surrounding function returns. Defer is commonly
|
||||
used to simplify functions that perform various clean-up actions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, let's look at a function that opens two files and copies the
|
||||
contents of one file to the other:
|
||||
</p>
|
||||
|
||||
{{code "progs/defer.go" `/func CopyFile/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This works, but there is a bug. If the call to os.Create fails, the
|
||||
function will return without closing the source file. This can be easily
|
||||
remedied by putting a call to src.Close() before the second return statement,
|
||||
but if the function were more complex the problem might not be so easily
|
||||
noticed and resolved. By introducing defer statements we can ensure that the
|
||||
files are always closed:
|
||||
</p>
|
||||
|
||||
{{code "progs/defer2.go" `/func CopyFile/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Defer statements allow us to think about closing each file right after opening
|
||||
it, guaranteeing that, regardless of the number of return statements in the
|
||||
function, the files <i>will</i> be closed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The behavior of defer statements is straightforward and predictable. There are
|
||||
three simple rules:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
1. <i>A deferred function's arguments are evaluated when the defer statement is
|
||||
evaluated.</i>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this example, the expression "i" is evaluated when the Println call is
|
||||
deferred. The deferred call will print "0" after the function returns.
|
||||
</p>
|
||||
|
||||
{{code "progs/defer.go" `/func a/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
2. <i>Deferred function calls are executed in Last In First Out order
|
||||
</i>after<i> the surrounding function returns.</i>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This function prints "3210":
|
||||
</p>
|
||||
|
||||
{{code "progs/defer.go" `/func b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
3. <i>Deferred functions may read and assign to the returning function's named
|
||||
return values.</i>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this example, a deferred function increments the return value i <i>after</i>
|
||||
the surrounding function returns. Thus, this function returns 2:
|
||||
</p>
|
||||
|
||||
{{code "progs/defer.go" `/func c/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This is convenient for modifying the error return value of a function; we will
|
||||
see an example of this shortly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Panic</b> is a built-in function that stops the ordinary flow of control and
|
||||
begins <i>panicking</i>. When the function F calls panic, execution of F stops,
|
||||
any deferred functions in F are executed normally, and then F returns to its
|
||||
caller. To the caller, F then behaves like a call to panic. The process
|
||||
continues up the stack until all functions in the current goroutine have
|
||||
returned, at which point the program crashes. Panics can be initiated by
|
||||
invoking panic directly. They can also be caused by runtime errors, such as
|
||||
out-of-bounds array accesses.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Recover</b> is a built-in function that regains control of a panicking
|
||||
goroutine. Recover is only useful inside deferred functions. During normal
|
||||
execution, a call to recover will return nil and have no other effect. If the
|
||||
current goroutine is panicking, a call to recover will capture the value given
|
||||
to panic and resume normal execution.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here's an example program that demonstrates the mechanics of panic and defer:
|
||||
</p>
|
||||
|
||||
{{code "progs/defer2.go" `/package main/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The function g takes the int i, and panics if i is greater than 3, or else it
|
||||
calls itself with the argument i+1. The function f defers a function that calls
|
||||
recover and prints the recovered value (if it is non-nil). Try to picture what
|
||||
the output of this program might be before reading on.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The program will output:
|
||||
</p>
|
||||
|
||||
<pre>Calling g.
|
||||
Printing in g 0
|
||||
Printing in g 1
|
||||
Printing in g 2
|
||||
Printing in g 3
|
||||
Panicking!
|
||||
Defer in g 3
|
||||
Defer in g 2
|
||||
Defer in g 1
|
||||
Defer in g 0
|
||||
Recovered in f 4
|
||||
Returned normally from f.</pre>
|
||||
|
||||
<p>
|
||||
If we remove the deferred function from f the panic is not recovered and
|
||||
reaches the top of the goroutine's call stack, terminating the program. This
|
||||
modified program will output:
|
||||
</p>
|
||||
|
||||
<pre>Calling g.
|
||||
Printing in g 0
|
||||
Printing in g 1
|
||||
Printing in g 2
|
||||
Printing in g 3
|
||||
Panicking!
|
||||
Defer in g 3
|
||||
Defer in g 2
|
||||
Defer in g 1
|
||||
Defer in g 0
|
||||
panic: 4
|
||||
|
||||
panic PC=0x2a9cd8
|
||||
[stack trace omitted]</pre>
|
||||
|
||||
<p>
|
||||
For a real-world example of <b>panic</b> and <b>recover</b>, see the
|
||||
<a href="/pkg/encoding/json/">json package</a> from the Go standard library.
|
||||
It decodes JSON-encoded data with a set of recursive functions.
|
||||
When malformed JSON is encountered, the parser calls panic to unwind the
|
||||
stack to the top-level function call, which recovers from the panic and returns
|
||||
an appropriate error value (see the 'error' and 'unmarshal' functions in
|
||||
<a href="/src/pkg/encoding/json/decode.go">decode.go</a>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The convention in the Go libraries is that even when a package uses panic
|
||||
internally, its external API still presents explicit error return values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Other uses of <b>defer</b> (beyond the file.Close() example given earlier)
|
||||
include releasing a mutex:
|
||||
</p>
|
||||
|
||||
<pre>mu.Lock()
|
||||
defer mu.Unlock()</pre>
|
||||
|
||||
<p>
|
||||
printing a footer:
|
||||
</p>
|
||||
|
||||
<pre>printHeader()
|
||||
defer printFooter()</pre>
|
||||
|
||||
<p>
|
||||
and more.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In summary, the defer statement (with or without panic and recover) provides an
|
||||
unusual and powerful mechanism for control flow. It can be used to model a
|
||||
number of features implemented by special-purpose structures in other
|
||||
programming languages. Try it out.
|
||||
</p>
|
@ -1,10 +1,7 @@
|
||||
<!--{
|
||||
"Title": "Error Handling and Go"
|
||||
"Title": "Error Handling and Go",
|
||||
"Template": true
|
||||
}-->
|
||||
<!--
|
||||
DO NOT EDIT: created by
|
||||
tmpltohtml articles/error_handling.tmpl
|
||||
-->
|
||||
|
||||
<p>
|
||||
If you have written any Go code you have probably encountered the built-in
|
||||
@ -13,20 +10,14 @@ indicate an abnormal state. For example, the <code>os.Open</code> function
|
||||
returns a non-nil <code>error</code> value when it fails to open a file.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/func Open/`}}
|
||||
-->func Open(name string) (file *File, err error)</pre>
|
||||
{{code "/doc/progs/error.go" `/func Open/`}}
|
||||
|
||||
<p>
|
||||
The following code uses <code>os.Open</code> to open a file. If an error
|
||||
occurs it calls <code>log.Fatal</code> to print the error message and stop.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/func openFile/` `/STOP/`}}
|
||||
--> f, err := os.Open("filename.ext")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// do something with the open *File f</pre>
|
||||
{{code "/doc/progs/error.go" `/func openFile/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
You can get a lot done in Go knowing just this about the <code>error</code>
|
||||
@ -59,15 +50,7 @@ The most commonly-used <code>error</code> implementation is the
|
||||
<a href="/pkg/errors/">errors</a> package's unexported <code>errorString</code> type.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/errorString/` `/STOP/`}}
|
||||
-->// errorString is a trivial implementation of error.
|
||||
type errorString struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (e *errorString) Error() string {
|
||||
return e.s
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/errorString/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
You can construct one of these values with the <code>errors.New</code>
|
||||
@ -75,23 +58,13 @@ function. It takes a string that it converts to an <code>errors.errorString</cod
|
||||
and returns as an <code>error</code> value.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/New/` `/STOP/`}}
|
||||
-->// New returns an error that formats as the given text.
|
||||
func New(text string) error {
|
||||
return &errorString{text}
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/New/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Here's how you might use <code>errors.New</code>:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/func Sqrt/` `/STOP/`}}
|
||||
-->func Sqrt(f float64) (float64, error) {
|
||||
if f < 0 {
|
||||
return 0, errors.New("math: square root of negative number")
|
||||
}
|
||||
// implementation
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/func Sqrt/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
A caller passing a negative argument to <code>Sqrt</code> receives a non-nil
|
||||
@ -101,11 +74,7 @@ A caller passing a negative argument to <code>Sqrt</code> receives a non-nil
|
||||
<code>Error</code> method, or by just printing it:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/func printErr/` `/STOP/`}}
|
||||
--> f, err := Sqrt(-1)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/func printErr/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/fmt/">fmt</a> package formats an <code>error</code> value
|
||||
@ -126,10 +95,7 @@ rules and returns it as an <code>error</code> created by
|
||||
<code>errors.New</code>.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/fmtError/` `/STOP/`}}
|
||||
--> if f < 0 {
|
||||
return 0, fmt.Errorf("math: square root of negative number %g", f)
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/fmtError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
In many cases <code>fmt.Errorf</code> is good enough, but since
|
||||
@ -143,12 +109,7 @@ argument passed to <code>Sqrt</code>. We can enable that by defining a new
|
||||
error implementation instead of using <code>errors.errorString</code>:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/type NegativeSqrtError/` `/STOP/`}}
|
||||
-->type NegativeSqrtError float64
|
||||
|
||||
func (f NegativeSqrtError) Error() string {
|
||||
return fmt.Sprintf("math: square root of negative number %g", float64(f))
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/type NegativeSqrtError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
A sophisticated caller can then use a
|
||||
@ -164,13 +125,7 @@ As another example, the <a href="/pkg/encoding/json/">json</a> package specifies
|
||||
returns when it encounters a syntax error parsing a JSON blob.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/type SyntaxError/` `/STOP/`}}
|
||||
-->type SyntaxError struct {
|
||||
msg string // description of error
|
||||
Offset int64 // error occurred after reading Offset bytes
|
||||
}
|
||||
|
||||
func (e *SyntaxError) Error() string { return e.msg }</pre>
|
||||
{{code "/doc/progs/error.go" `/type SyntaxError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The <code>Offset</code> field isn't even shown in the default formatting of the
|
||||
@ -178,14 +133,7 @@ error, but callers can use it to add file and line information to their error
|
||||
messages:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/func decodeError/` `/STOP/`}}
|
||||
--> if err := dec.Decode(&val); err != nil {
|
||||
if serr, ok := err.(*json.SyntaxError); ok {
|
||||
line, col := findLine(f, serr.Offset)
|
||||
return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
|
||||
}
|
||||
return err
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/func decodeError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
(This is a slightly simplified version of some
|
||||
@ -217,14 +165,7 @@ web crawler might sleep and retry when it encounters a temporary error and give
|
||||
up otherwise.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error.go" `/func netError/` `/STOP/`}}
|
||||
--> if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
|
||||
time.Sleep(1e9)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}</pre>
|
||||
{{code "/doc/progs/error.go" `/func netError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
<b>Simplifying repetitive error handling</b>
|
||||
@ -244,23 +185,7 @@ application with an HTTP handler that retrieves a record from the datastore and
|
||||
formats it with a template.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error2.go" `/func init/` `/STOP/`}}
|
||||
-->func init() {
|
||||
http.HandleFunc("/view", viewRecord)
|
||||
}
|
||||
|
||||
func viewRecord(w http.ResponseWriter, r *http.Request) {
|
||||
c := appengine.NewContext(r)
|
||||
key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
|
||||
record := new(Record)
|
||||
if err := datastore.Get(c, key, record); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
if err := viewTemplate.Execute(w, record); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
}
|
||||
}</pre>
|
||||
{{code "/doc/progs/error2.go" `/func init/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This function handles errors returned by the <code>datastore.Get</code>
|
||||
@ -276,23 +201,13 @@ To reduce the repetition we can define our own HTTP <code>appHandler</code>
|
||||
type that includes an <code>error</code> return value:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error3.go" `/type appHandler/`}}
|
||||
-->type appHandler func(http.ResponseWriter, *http.Request) error</pre>
|
||||
{{code "/doc/progs/error3.go" `/type appHandler/`}}
|
||||
|
||||
<p>
|
||||
Then we can change our <code>viewRecord</code> function to return errors:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error3.go" `/func viewRecord/` `/STOP/`}}
|
||||
-->func viewRecord(w http.ResponseWriter, r *http.Request) error {
|
||||
c := appengine.NewContext(r)
|
||||
key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
|
||||
record := new(Record)
|
||||
if err := datastore.Get(c, key, record); err != nil {
|
||||
return err
|
||||
}
|
||||
return viewTemplate.Execute(w, record)
|
||||
}</pre>
|
||||
{{code "/doc/progs/error3.go" `/func viewRecord/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This is simpler than the original version, but the <a
|
||||
@ -302,12 +217,7 @@ To fix this we can implement the <code>http.Handler</code> interface's
|
||||
<code>ServeHTTP</code> method on <code>appHandler</code>:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error3.go" `/ServeHTTP/` `/STOP/`}}
|
||||
-->func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if err := fn(w, r); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
}
|
||||
}</pre>
|
||||
{{code "/doc/progs/error3.go" `/ServeHTTP/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The <code>ServeHTTP</code> method calls the <code>appHandler</code> function
|
||||
@ -323,10 +233,7 @@ Now when registering <code>viewRecord</code> with the http package we use the
|
||||
<code>http.HandlerFunc</code>).
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error3.go" `/func init/` `/STOP/`}}
|
||||
-->func init() {
|
||||
http.Handle("/view", appHandler(viewRecord))
|
||||
}</pre>
|
||||
{{code "/doc/progs/error3.go" `/func init/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
With this basic error handling infrastructure in place, we can make it more
|
||||
@ -341,19 +248,13 @@ To do this we create an <code>appError</code> struct containing an
|
||||
<code>error</code> and some other fields:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error4.go" `/type appError/` `/STOP/`}}
|
||||
-->type appError struct {
|
||||
Error error
|
||||
Message string
|
||||
Code int
|
||||
}</pre>
|
||||
{{code "/doc/progs/error4.go" `/type appError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Next we modify the appHandler type to return <code>*appError</code> values:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error4.go" `/type appHandler/`}}
|
||||
-->type appHandler func(http.ResponseWriter, *http.Request) *appError</pre>
|
||||
{{code "/doc/progs/error4.go" `/type appHandler/`}}
|
||||
|
||||
<p>
|
||||
(It's usually a mistake to pass back the concrete type of an error rather than
|
||||
@ -369,33 +270,14 @@ status <code>Code</code> and log the full <code>Error</code> to the developer
|
||||
console:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error4.go" `/ServeHTTP/` `/STOP/`}}
|
||||
-->func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if e := fn(w, r); e != nil { // e is *appError, not os.Error.
|
||||
c := appengine.NewContext(r)
|
||||
c.Errorf("%v", e.Error)
|
||||
http.Error(w, e.Message, e.Code)
|
||||
}
|
||||
}</pre>
|
||||
{{code "/doc/progs/error4.go" `/ServeHTTP/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Finally, we update <code>viewRecord</code> to the new function signature and
|
||||
have it return more context when it encounters an error:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/error4.go" `/func viewRecord/` `/STOP/`}}
|
||||
-->func viewRecord(w http.ResponseWriter, r *http.Request) *appError {
|
||||
c := appengine.NewContext(r)
|
||||
key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
|
||||
record := new(Record)
|
||||
if err := datastore.Get(c, key, record); err != nil {
|
||||
return &appError{err, "Record not found", 404}
|
||||
}
|
||||
if err := viewTemplate.Execute(w, record); err != nil {
|
||||
return &appError{err, "Can't display record", 500}
|
||||
}
|
||||
return nil
|
||||
}</pre>
|
||||
{{code "/doc/progs/error4.go" `/func viewRecord/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This version of <code>viewRecord</code> is the same length as the original, but
|
||||
|
@ -1,314 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Error Handling and Go"
|
||||
}-->
|
||||
{{donotedit}}
|
||||
<p>
|
||||
If you have written any Go code you have probably encountered the built-in
|
||||
<code>error</code> type. Go code uses <code>error</code> values to
|
||||
indicate an abnormal state. For example, the <code>os.Open</code> function
|
||||
returns a non-nil <code>error</code> value when it fails to open a file.
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/func Open/`}}
|
||||
|
||||
<p>
|
||||
The following code uses <code>os.Open</code> to open a file. If an error
|
||||
occurs it calls <code>log.Fatal</code> to print the error message and stop.
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/func openFile/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
You can get a lot done in Go knowing just this about the <code>error</code>
|
||||
type, but in this article we'll take a closer look at <code>error</code> and
|
||||
discuss some good practices for error handling in Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>The error type</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>error</code> type is an interface type. An <code>error</code>
|
||||
variable represents any value that can describe itself as a string. Here is the
|
||||
interface's declaration:
|
||||
</p>
|
||||
|
||||
<pre>type error interface {
|
||||
Error() string
|
||||
}</pre>
|
||||
|
||||
<p>
|
||||
The <code>error</code> type, as with all built in types, is
|
||||
<a href="/doc/go_spec.html#Predeclared_identifiers">predeclared</a> in the
|
||||
<a href="/doc/go_spec.html#Blocks">universe block</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The most commonly-used <code>error</code> implementation is the
|
||||
<a href="/pkg/errors/">errors</a> package's unexported <code>errorString</code> type.
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/errorString/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
You can construct one of these values with the <code>errors.New</code>
|
||||
function. It takes a string that it converts to an <code>errors.errorString</code>
|
||||
and returns as an <code>error</code> value.
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/New/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Here's how you might use <code>errors.New</code>:
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/func Sqrt/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
A caller passing a negative argument to <code>Sqrt</code> receives a non-nil
|
||||
<code>error</code> value (whose concrete representation is an
|
||||
<code>errors.errorString</code> value). The caller can access the error string
|
||||
("math: square root of...") by calling the <code>error</code>'s
|
||||
<code>Error</code> method, or by just printing it:
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/func printErr/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/fmt/">fmt</a> package formats an <code>error</code> value
|
||||
by calling its <code>Error() string</code> method.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is the error implementation's responsibility to summarize the context.
|
||||
The error returned by <code>os.Open</code> formats as "open /etc/passwd:
|
||||
permission denied," not just "permission denied." The error returned by our
|
||||
<code>Sqrt</code> is missing information about the invalid argument.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To add that information, a useful function is the <code>fmt</code> package's
|
||||
<code>Errorf</code>. It formats a string according to <code>Printf</code>'s
|
||||
rules and returns it as an <code>error</code> created by
|
||||
<code>errors.New</code>.
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/fmtError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
In many cases <code>fmt.Errorf</code> is good enough, but since
|
||||
<code>error</code> is an interface, you can use arbitrary data structures as
|
||||
error values, to allow callers to inspect the details of the error.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For instance, our hypothetical callers might want to recover the invalid
|
||||
argument passed to <code>Sqrt</code>. We can enable that by defining a new
|
||||
error implementation instead of using <code>errors.errorString</code>:
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/type NegativeSqrtError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
A sophisticated caller can then use a
|
||||
<a href="/doc/go_spec.html#Type_assertions">type assertion</a> to check for a
|
||||
<code>NegativeSqrtError</code> and handle it specially, while callers that just
|
||||
pass the error to <code>fmt.Println</code> or <code>log.Fatal</code> will see
|
||||
no change in behavior.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As another example, the <a href="/pkg/encoding/json/">json</a> package specifies a
|
||||
<code>SyntaxError</code> type that the <code>json.Decode</code> function
|
||||
returns when it encounters a syntax error parsing a JSON blob.
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/type SyntaxError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The <code>Offset</code> field isn't even shown in the default formatting of the
|
||||
error, but callers can use it to add file and line information to their error
|
||||
messages:
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/func decodeError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
(This is a slightly simplified version of some
|
||||
<a href="http://camlistore.org/code/?p=camlistore.git;a=blob;f=lib/go/camli/jsonconfig/eval.go#l68">actual code</a>
|
||||
from the <a href="http://camlistore.org">Camlistore</a> project.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>error</code> interface requires only a <code>Error</code> method;
|
||||
specific error implementations might have additional methods. For instance, the
|
||||
<a href="/pkg/net/">net</a> package returns errors of type
|
||||
<code>error</code>, following the usual convention, but some of the error
|
||||
implementations have additional methods defined by the <code>net.Error</code>
|
||||
interface:
|
||||
</p>
|
||||
|
||||
<pre>package net
|
||||
|
||||
type Error interface {
|
||||
error
|
||||
Timeout() bool // Is the error a timeout?
|
||||
Temporary() bool // Is the error temporary?
|
||||
}</pre>
|
||||
|
||||
<p>
|
||||
Client code can test for a <code>net.Error</code> with a type assertion and
|
||||
then distinguish transient network errors from permanent ones. For instance, a
|
||||
web crawler might sleep and retry when it encounters a temporary error and give
|
||||
up otherwise.
|
||||
</p>
|
||||
|
||||
{{code "progs/error.go" `/func netError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
<b>Simplifying repetitive error handling</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In Go, error handling is important. The language's design and conventions
|
||||
encourage you to explicitly check for errors where they occur (as distinct from
|
||||
the convention in other languages of throwing exceptions and sometimes catching
|
||||
them). In some cases this makes Go code verbose, but fortunately there are some
|
||||
techniques you can use to minimize repetitive error handling.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Consider an <a href="http://code.google.com/appengine/docs/go/">App Engine</a>
|
||||
application with an HTTP handler that retrieves a record from the datastore and
|
||||
formats it with a template.
|
||||
</p>
|
||||
|
||||
{{code "progs/error2.go" `/func init/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This function handles errors returned by the <code>datastore.Get</code>
|
||||
function and <code>viewTemplate</code>'s <code>Execute</code> method. In both
|
||||
cases, it presents a simple error message to the user with the HTTP status code
|
||||
500 ("Internal Server Error"). This looks like a manageable amount of code, but
|
||||
add some more HTTP handlers and you quickly end up with many copies of
|
||||
identical error handling code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To reduce the repetition we can define our own HTTP <code>appHandler</code>
|
||||
type that includes an <code>error</code> return value:
|
||||
</p>
|
||||
|
||||
{{code "progs/error3.go" `/type appHandler/`}}
|
||||
|
||||
<p>
|
||||
Then we can change our <code>viewRecord</code> function to return errors:
|
||||
</p>
|
||||
|
||||
{{code "progs/error3.go" `/func viewRecord/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This is simpler than the original version, but the <a
|
||||
href="/pkg/net/http/">http</a> package doesn't understand functions that return
|
||||
<code>error</code>.
|
||||
To fix this we can implement the <code>http.Handler</code> interface's
|
||||
<code>ServeHTTP</code> method on <code>appHandler</code>:
|
||||
</p>
|
||||
|
||||
{{code "progs/error3.go" `/ServeHTTP/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The <code>ServeHTTP</code> method calls the <code>appHandler</code> function
|
||||
and displays the returned error (if any) to the user. Notice that the method's
|
||||
receiver, <code>fn</code>, is a function. (Go can do that!) The method invokes
|
||||
the function by calling the receiver in the expression <code>fn(w, r)</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now when registering <code>viewRecord</code> with the http package we use the
|
||||
<code>Handle</code> function (instead of <code>HandleFunc</code>) as
|
||||
<code>appHandler</code> is an <code>http.Handler</code> (not an
|
||||
<code>http.HandlerFunc</code>).
|
||||
</p>
|
||||
|
||||
{{code "progs/error3.go" `/func init/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
With this basic error handling infrastructure in place, we can make it more
|
||||
user friendly. Rather than just displaying the error string, it would be better
|
||||
to give the user a simple error message with an appropriate HTTP status code,
|
||||
while logging the full error to the App Engine developer console for debugging
|
||||
purposes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To do this we create an <code>appError</code> struct containing an
|
||||
<code>error</code> and some other fields:
|
||||
</p>
|
||||
|
||||
{{code "progs/error4.go" `/type appError/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Next we modify the appHandler type to return <code>*appError</code> values:
|
||||
</p>
|
||||
|
||||
{{code "progs/error4.go" `/type appHandler/`}}
|
||||
|
||||
<p>
|
||||
(It's usually a mistake to pass back the concrete type of an error rather than
|
||||
<code>error</code>, for reasons to be discussed in another article, but
|
||||
it's the right thing to do here because <code>ServeHTTP</code> is the only
|
||||
place that sees the value and uses its contents.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
And make <code>appHandler</code>'s <code>ServeHTTP</code> method display the
|
||||
<code>appError</code>'s <code>Message</code> to the user with the correct HTTP
|
||||
status <code>Code</code> and log the full <code>Error</code> to the developer
|
||||
console:
|
||||
</p>
|
||||
|
||||
{{code "progs/error4.go" `/ServeHTTP/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Finally, we update <code>viewRecord</code> to the new function signature and
|
||||
have it return more context when it encounters an error:
|
||||
</p>
|
||||
|
||||
{{code "progs/error4.go" `/func viewRecord/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This version of <code>viewRecord</code> is the same length as the original, but
|
||||
now each of those lines has specific meaning and we are providing a friendlier
|
||||
user experience.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It doesn't end there; we can further improve the error handling in our
|
||||
application. Some ideas:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>give the error handler a pretty HTML template,
|
||||
<li>make debugging easier by writing the stack trace to the HTTP response when
|
||||
the user is an administrator,
|
||||
<li>write a constructor function for <code>appError</code> that stores the
|
||||
stack trace for easier debugging,
|
||||
<li>recover from panics inside the <code>appHandler</code>, logging the error
|
||||
to the console as "Critical," while telling the user "a serious error
|
||||
has occurred." This is a nice touch to avoid exposing the user to inscrutable
|
||||
error messages caused by programming errors.
|
||||
See the <a href="defer_panic_recover.html">Defer, Panic, and Recover</a>
|
||||
article for more details.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<b>Conclusion</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Proper error handling is an essential requirement of good software. By
|
||||
employing the techniques described in this post you should be able to write
|
||||
more reliable and succinct Go code.
|
||||
</p>
|
@ -1,11 +1,7 @@
|
||||
<!--{
|
||||
"Title": "The Laws of Reflection"
|
||||
"Title": "The Laws of Reflection",
|
||||
"Template": true
|
||||
}-->
|
||||
<!--
|
||||
DO NOT EDIT: created by
|
||||
tmpltohtml articles/laws_of_reflection.tmpl
|
||||
-->
|
||||
|
||||
|
||||
<p>
|
||||
Reflection in computing is the
|
||||
@ -36,11 +32,7 @@ exactly one type known and fixed at compile time: <code>int</code>,
|
||||
and so on. If we declare
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface.go" `/type MyInt/` `/STOP/`}}
|
||||
-->type MyInt int
|
||||
|
||||
var i int
|
||||
var j MyInt</pre>
|
||||
{{code "/doc/progs/interface.go" `/type MyInt/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
then <code>i</code> has type <code>int</code> and <code>j</code>
|
||||
@ -60,16 +52,7 @@ interface's methods. A well-known pair of examples is
|
||||
"http://golang.org/pkg/io/">io package</a>:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface.go" `/// Reader/` `/STOP/`}}
|
||||
-->// Reader is the interface that wraps the basic Read method.
|
||||
type Reader interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
|
||||
// Writer is the interface that wraps the basic Write method.
|
||||
type Writer interface {
|
||||
Write(p []byte) (n int, err error)
|
||||
}</pre>
|
||||
{{code "/doc/progs/interface.go" `/// Reader/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Any type that implements a <code>Read</code> (or
|
||||
@ -80,12 +63,7 @@ purposes of this discussion, that means that a variable of type
|
||||
<code>Read</code> method:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface.go" `/func readers/` `/STOP/`}}
|
||||
--> var r io.Reader
|
||||
r = os.Stdin
|
||||
r = bufio.NewReader(r)
|
||||
r = new(bytes.Buffer)
|
||||
// and so on</pre>
|
||||
{{code "/doc/progs/interface.go" `/func readers/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
It's important to be clear that whatever concrete value
|
||||
@ -138,13 +116,7 @@ that implements the interface and the type describes the full type
|
||||
of that item. For instance, after
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface.go" `/func typeAssertions/` `/STOP/`}}
|
||||
--> var r io.Reader
|
||||
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r = tty</pre>
|
||||
{{code "/doc/progs/interface.go" `/func typeAssertions/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
<code>r</code> contains, schematically, the (value, type) pair,
|
||||
@ -156,9 +128,7 @@ the type information about that value. That's why we can do things
|
||||
like this:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface.go" `/var w io.Writer/` `/STOP/`}}
|
||||
--> var w io.Writer
|
||||
w = r.(io.Writer)</pre>
|
||||
{{code "/doc/progs/interface.go" `/var w io.Writer/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The expression in this assignment is a type assertion; what it
|
||||
@ -176,9 +146,7 @@ methods.
|
||||
Continuing, we can do this:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface.go" `/var empty interface{}/` `/STOP/`}}
|
||||
--> var empty interface{}
|
||||
empty = w</pre>
|
||||
{{code "/doc/progs/interface.go" `/var empty interface{}/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
and our empty interface value <code>e</code> will again contain
|
||||
@ -232,18 +200,7 @@ now.)
|
||||
Let's start with <code>TypeOf</code>:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/package main/` `/STOP main/`}}
|
||||
-->package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var x float64 = 3.4
|
||||
fmt.Println("type:", reflect.TypeOf(x))
|
||||
}</pre>
|
||||
{{code "/doc/progs/interface2.go" `/package main/` `/STOP main/`}}
|
||||
|
||||
<p>
|
||||
This program prints
|
||||
@ -281,9 +238,7 @@ value (from here on we'll elide the boilerplate and focus just on
|
||||
the executable code):
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/var x/` `/STOP/`}}
|
||||
--> var x float64 = 3.4
|
||||
fmt.Println("type:", reflect.TypeOf(x))</pre>
|
||||
{{code "/doc/progs/interface2.go" `/var x/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
prints
|
||||
@ -307,12 +262,7 @@ on. Also methods on <code>Value</code> with names like
|
||||
<code>int64</code> and <code>float64</code>) stored inside:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f1/` `/STOP/`}}
|
||||
--> var x float64 = 3.4
|
||||
v := reflect.ValueOf(x)
|
||||
fmt.Println("type:", v.Type())
|
||||
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
|
||||
fmt.Println("value:", v.Float())</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f1/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
prints
|
||||
@ -342,12 +292,7 @@ instance. That is, the <code>Int</code> method of
|
||||
necessary to convert to the actual type involved:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f2/` `/STOP/`}}
|
||||
--> var x uint8 = 'x'
|
||||
v := reflect.ValueOf(x)
|
||||
fmt.Println("type:", v.Type()) // uint8.
|
||||
fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
|
||||
x = uint8(v.Uint()) // v.Uint returns a uint64.</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f2/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The second property is that the <code>Kind</code> of a reflection
|
||||
@ -356,10 +301,7 @@ reflection object contains a value of a user-defined integer type,
|
||||
as in
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f3/` `/STOP/`}}
|
||||
--> type MyInt int
|
||||
var x MyInt = 7
|
||||
v := reflect.ValueOf(x)</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f3/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
the <code>Kind</code> of <code>v</code> is still
|
||||
@ -395,9 +337,7 @@ func (v Value) Interface() interface{}
|
||||
As a consequence we can say
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f3b/` `/STOP/`}}
|
||||
--> y := v.Interface().(float64) // y will have type float64.
|
||||
fmt.Println(y)</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f3b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
to print the <code>float64</code> value represented by the
|
||||
@ -415,8 +355,7 @@ the <code>Interface</code> method to the formatted print
|
||||
routine:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f3c/` `/STOP/`}}
|
||||
--> fmt.Println(v.Interface())</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f3c/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
(Why not <code>fmt.Println(v)</code>? Because <code>v</code> is a
|
||||
@ -425,8 +364,7 @@ Since our value is a <code>float64</code>, we can even use a
|
||||
floating-point format if we want:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f3d/` `/STOP/`}}
|
||||
--> fmt.Printf("value is %7.1e\n", v.Interface())</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f3d/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
and get in this case
|
||||
@ -467,10 +405,7 @@ enough to understand if we start from first principles.
|
||||
Here is some code that does not work, but is worth studying.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f4/` `/STOP/`}}
|
||||
--> var x float64 = 3.4
|
||||
v := reflect.ValueOf(x)
|
||||
v.SetFloat(7.1) // Error: will panic.</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f4/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
If you run this code, it will panic with the cryptic message
|
||||
@ -492,10 +427,7 @@ The <code>CanSet</code> method of <code>Value</code> reports the
|
||||
settability of a <code>Value</code>; in our case,
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f5/` `/STOP/`}}
|
||||
--> var x float64 = 3.4
|
||||
v := reflect.ValueOf(x)
|
||||
fmt.Println("settability of v:", v.CanSet())</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f5/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
prints
|
||||
@ -518,9 +450,7 @@ determined by whether the reflection object holds the original
|
||||
item. When we say
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f6/` `/STOP/`}}
|
||||
--> var x float64 = 3.4
|
||||
v := reflect.ValueOf(x)</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f6/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
we pass a <em>copy</em> of <code>x</code> to
|
||||
@ -530,8 +460,7 @@ argument to <code>reflect.ValueOf</code> is a <em>copy</em> of
|
||||
statement
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f6b/` `/STOP/`}}
|
||||
--> v.SetFloat(7.1)</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f6b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
were allowed to succeed, it would not update <code>x</code>, even
|
||||
@ -577,11 +506,7 @@ and then create a reflection value that points to it, called
|
||||
<code>p</code>.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f7/` `/STOP/`}}
|
||||
--> var x float64 = 3.4
|
||||
p := reflect.ValueOf(&x) // Note: take the address of x.
|
||||
fmt.Println("type of p:", p.Type())
|
||||
fmt.Println("settability of p:", p.CanSet())</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f7/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The output so far is
|
||||
@ -601,9 +526,7 @@ and save the result in a reflection <code>Value</code> called
|
||||
<code>v</code>:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f7b/` `/STOP/`}}
|
||||
--> v := p.Elem()
|
||||
fmt.Println("settability of v:", v.CanSet())</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f7b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Now <code>v</code> is a settable reflection object, as the output
|
||||
@ -620,10 +543,7 @@ and since it represents <code>x</code>, we are finally able to use
|
||||
<code>x</code>:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f7c/` `/STOP/`}}
|
||||
--> v.SetFloat(7.1)
|
||||
fmt.Println(v.Interface())
|
||||
fmt.Println(x)</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f7c/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The output, as expected, is
|
||||
@ -664,19 +584,7 @@ but the fields themselves are regular <code>reflect.Value</code>
|
||||
objects.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f8/` `/STOP/`}}
|
||||
--> type T struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
t := T{23, "skidoo"}
|
||||
s := reflect.ValueOf(&t).Elem()
|
||||
typeOfT := s.Type()
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
f := s.Field(i)
|
||||
fmt.Printf("%d: %s %s = %v\n", i,
|
||||
typeOfT.Field(i).Name, f.Type(), f.Interface())
|
||||
}</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f8/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The output of this program is
|
||||
@ -699,10 +607,7 @@ Because <code>s</code> contains a settable reflection object, we
|
||||
can modify the fields of the structure.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/interface2.go" `/START f8b/` `/STOP/`}}
|
||||
--> s.Field(0).SetInt(77)
|
||||
s.Field(1).SetString("Sunset Strip")
|
||||
fmt.Println("t is now", t)</pre>
|
||||
{{code "/doc/progs/interface2.go" `/START f8b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
And here's the result:
|
||||
@ -746,4 +651,4 @@ sending and receiving on channels, allocating memory, using slices
|
||||
and maps, calling methods and functions — but this post is
|
||||
long enough. We'll cover some of those topics in a later
|
||||
article.
|
||||
</p>
|
||||
</p>
|
||||
|
@ -1,654 +0,0 @@
|
||||
<!--{
|
||||
"Title": "The Laws of Reflection"
|
||||
}-->
|
||||
{{donotedit}}
|
||||
|
||||
<p>
|
||||
Reflection in computing is the
|
||||
ability of a program to examine its own structure, particularly
|
||||
through types; it's a form of metaprogramming. It's also a great
|
||||
source of confusion.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In this article we attempt to clarify things by explaining how
|
||||
reflection works in Go. Each language's reflection model is
|
||||
different (and many languages don't support it at all), but
|
||||
this article is about Go, so for the rest of this article the word
|
||||
"reflection" should be taken to mean "reflection in Go".
|
||||
</p>
|
||||
|
||||
<p><b>Types and interfaces</b></p>
|
||||
|
||||
<p>
|
||||
Because reflection builds on the type system, let's start with a
|
||||
refresher about types in Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go is statically typed. Every variable has a static type, that is,
|
||||
exactly one type known and fixed at compile time: <code>int</code>,
|
||||
<code>float32</code>, <code>*MyType</code>, <code>[]byte</code>,
|
||||
and so on. If we declare
|
||||
</p>
|
||||
|
||||
{{code "progs/interface.go" `/type MyInt/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
then <code>i</code> has type <code>int</code> and <code>j</code>
|
||||
has type <code>MyInt</code>. The variables <code>i</code> and
|
||||
<code>j</code> have distinct static types and, although they have
|
||||
the same underlying type, they cannot be assigned to one another
|
||||
without a conversion.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One important category of type is interface types, which represent
|
||||
fixed sets of methods. An interface variable can store any concrete
|
||||
(non-interface) value as long as that value implements the
|
||||
interface's methods. A well-known pair of examples is
|
||||
<code>io.Reader</code> and <code>io.Writer</code>, the types
|
||||
<code>Reader</code> and <code>Writer</code> from the <a href=
|
||||
"http://golang.org/pkg/io/">io package</a>:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface.go" `/// Reader/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Any type that implements a <code>Read</code> (or
|
||||
<code>Write</code>) method with this signature is said to implement
|
||||
<code>io.Reader</code> (or <code>io.Writer</code>). For the
|
||||
purposes of this discussion, that means that a variable of type
|
||||
<code>io.Reader</code> can hold any value whose type has a
|
||||
<code>Read</code> method:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface.go" `/func readers/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
It's important to be clear that whatever concrete value
|
||||
<code>r</code> may hold, <code>r</code>'s type is always
|
||||
<code>io.Reader</code>: Go is statically typed and the static type
|
||||
of <code>r</code> is <code>io.Reader</code>.</p>
|
||||
|
||||
<p>
|
||||
An extremely important example of an interface type is the empty
|
||||
interface:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
interface{}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
It represents the empty set of methods and is satisfied by any
|
||||
value at all, since any value has zero or more methods.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Some people say that Go's interfaces are dynamically typed, but
|
||||
that is misleading. They are statically typed: a variable of
|
||||
interface type always has the same static type, and even though at
|
||||
run time the value stored in the interface variable may change
|
||||
type, that value will always satisfy the interface.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We need to be precise about all this because reflection and
|
||||
interfaces are closely related.
|
||||
</p>
|
||||
|
||||
<p><b>The representation of an interface</b></p>
|
||||
|
||||
<p>
|
||||
Russ Cox has written a <a href=
|
||||
"http://research.swtch.com/2009/12/go-data-structures-interfaces.html">
|
||||
detailed blog post</a> about the representation of interface values
|
||||
in Go. It's not necessary to repeat the full story here, but a
|
||||
simplified summary is in order.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A variable of interface type stores a pair: the concrete value
|
||||
assigned to the variable, and that value's type descriptor.
|
||||
To be more precise, the value is the underlying concrete data item
|
||||
that implements the interface and the type describes the full type
|
||||
of that item. For instance, after
|
||||
</p>
|
||||
|
||||
{{code "progs/interface.go" `/func typeAssertions/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
<code>r</code> contains, schematically, the (value, type) pair,
|
||||
(<code>tty</code>, <code>*os.File</code>). Notice that the type
|
||||
<code>*os.File</code> implements methods other than
|
||||
<code>Read</code>; even though the interface value provides access
|
||||
only to the <code>Read</code> method, the value inside carries all
|
||||
the type information about that value. That's why we can do things
|
||||
like this:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface.go" `/var w io.Writer/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The expression in this assignment is a type assertion; what it
|
||||
asserts is that the item inside <code>r</code> also implements
|
||||
<code>io.Writer</code>, and so we can assign it to <code>w</code>.
|
||||
After the assignment, <code>w</code> will contain the pair
|
||||
(<code>tty</code>, <code>*os.File</code>). That's the same pair as
|
||||
was held in <code>r</code>. The static type of the interface
|
||||
determines what methods may be invoked with an interface variable,
|
||||
even though the concrete value inside may have a larger set of
|
||||
methods.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Continuing, we can do this:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface.go" `/var empty interface{}/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
and our empty interface value <code>e</code> will again contain
|
||||
that same pair, (<code>tty</code>, <code>*os.File</code>). That's
|
||||
handy: an empty interface can hold any value and contains all the
|
||||
information we could ever need about that value.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
(We don't need a type assertion here because it's known statically
|
||||
that <code>w</code> satisfies the empty interface. In the example
|
||||
where we moved a value from a <code>Reader</code> to a
|
||||
<code>Writer</code>, we needed to be explicit and use a type
|
||||
assertion because <code>Writer</code>'s methods are not a
|
||||
subset of <code>Reader</code>'s.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One important detail is that the pair inside an interface always
|
||||
has the form (value, concrete type) and cannot have the form
|
||||
(value, interface type). Interfaces do not hold interface
|
||||
values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now we're ready to reflect.
|
||||
</p>
|
||||
|
||||
<p><b>The first law of reflection</b></p>
|
||||
|
||||
<p><b>1. Reflection goes from interface value to reflection object.</b></p>
|
||||
|
||||
<p>
|
||||
At the basic level, reflection is just a mechanism to examine the
|
||||
type and value pair stored inside an interface variable. To get
|
||||
started, there are two types we need to know about in
|
||||
<a href="http://golang.org/pkg/reflect">package reflect</a>:
|
||||
<a href="http://golang.org/pkg/reflect/#Type">Type</a> and
|
||||
<a href="http://golang.org/pkg/reflect/#Value">Value</a>. Those two types
|
||||
give access to the contents of an interface variable, and two
|
||||
simple functions, called <code>reflect.TypeOf</code> and
|
||||
<code>reflect.ValueOf</code>, retrieve <code>reflect.Type</code>
|
||||
and <code>reflect.Value</code> pieces out of an interface value.
|
||||
(Also, from the <code>reflect.Value</code> it's easy to get
|
||||
to the <code>reflect.Type</code>, but let's keep the
|
||||
<code>Value</code> and <code>Type</code> concepts separate for
|
||||
now.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's start with <code>TypeOf</code>:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/package main/` `/STOP main/`}}
|
||||
|
||||
<p>
|
||||
This program prints
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type: float64
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You might be wondering where the interface is here, since the
|
||||
program looks like it's passing the <code>float64</code>
|
||||
variable <code>x</code>, not an interface value, to
|
||||
<code>reflect.TypeOf</code>. But it's there; as <a href=
|
||||
"http://golang.org/pkg/reflect/#Type.TypeOf">godoc reports</a>, the
|
||||
signature of <code>reflect.TypeOf</code> includes an empty
|
||||
interface:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// TypeOf returns the reflection Type of the value in the interface{}.
|
||||
func TypeOf(i interface{}) Type
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
When we call <code>reflect.TypeOf(x)</code>, <code>x</code> is
|
||||
first stored in an empty interface, which is then passed as the
|
||||
argument; <code>reflect.TypeOf</code> unpacks that empty interface
|
||||
to recover the type information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>reflect.ValueOf</code> function, of course, recovers the
|
||||
value (from here on we'll elide the boilerplate and focus just on
|
||||
the executable code):
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/var x/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
prints
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
value: <float64 Value>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Both <code>reflect.Type</code> and <code>reflect.Value</code> have
|
||||
lots of methods to let us examine and manipulate them. One
|
||||
important example is that <code>Value</code> has a
|
||||
<code>Type</code> method that returns the <code>Type</code> of a
|
||||
<code>reflect.Value</code>. Another is that both <code>Type</code>
|
||||
and <code>Value</code> have a <code>Kind</code> method that returns
|
||||
a constant indicating what sort of item is stored:
|
||||
<code>Uint</code>, <code>Float64</code>, <code>Slice</code>, and so
|
||||
on. Also methods on <code>Value</code> with names like
|
||||
<code>Int</code> and <code>Float</code> let us grab values (as
|
||||
<code>int64</code> and <code>float64</code>) stored inside:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f1/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
prints
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type: float64
|
||||
kind is float64: true
|
||||
value: 3.4
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
There are also methods like <code>SetInt</code> and
|
||||
<code>SetFloat</code> but to use them we need to understand
|
||||
settability, the subject of the third law of reflection, discussed
|
||||
below.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The reflection library has a couple of properties worth singling
|
||||
out. First, to keep the API simple, the "getter" and "setter"
|
||||
methods of <code>Value</code> operate on the largest type that can
|
||||
hold the value: <code>int64</code> for all the signed integers, for
|
||||
instance. That is, the <code>Int</code> method of
|
||||
<code>Value</code> returns an <code>int64</code> and the
|
||||
<code>SetInt</code> value takes an <code>int64</code>; it may be
|
||||
necessary to convert to the actual type involved:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f2/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The second property is that the <code>Kind</code> of a reflection
|
||||
object describes the underlying type, not the static type. If a
|
||||
reflection object contains a value of a user-defined integer type,
|
||||
as in
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f3/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
the <code>Kind</code> of <code>v</code> is still
|
||||
<code>reflect.Int</code>, even though the static type of
|
||||
<code>x</code> is <code>MyInt</code>, not <code>int</code>. In
|
||||
other words, the <code>Kind</code> cannot discriminate an int from
|
||||
a <code>MyInt</code> even though the <code>Type</code> can.
|
||||
</p>
|
||||
|
||||
<p><b>The second law of reflection</b></p>
|
||||
|
||||
<p><b>2. Reflection goes from reflection object to interface
|
||||
value.</b></p>
|
||||
|
||||
<p>
|
||||
Like physical reflection, reflection in Go generates its own
|
||||
inverse.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given a <code>reflect.Value</code> we can recover an interface
|
||||
value using the <code>Interface</code> method; in effect the method
|
||||
packs the type and value information back into an interface
|
||||
representation and returns the result:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// Interface returns v's value as an interface{}.
|
||||
func (v Value) Interface() interface{}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As a consequence we can say
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f3b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
to print the <code>float64</code> value represented by the
|
||||
reflection object <code>v</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We can do even better, though. The arguments to
|
||||
<code>fmt.Println</code>, <code>fmt.Printf</code> and so on are all
|
||||
passed as empty interface values, which are then unpacked by the
|
||||
<code>fmt</code> package internally just as we have been doing in
|
||||
the previous examples. Therefore all it takes to print the contents
|
||||
of a <code>reflect.Value</code> correctly is to pass the result of
|
||||
the <code>Interface</code> method to the formatted print
|
||||
routine:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f3c/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
(Why not <code>fmt.Println(v)</code>? Because <code>v</code> is a
|
||||
<code>reflect.Value</code>; we want the concrete value it holds.)
|
||||
Since our value is a <code>float64</code>, we can even use a
|
||||
floating-point format if we want:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f3d/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
and get in this case
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
3.4e+00
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Again, there's no need to type-assert the result of
|
||||
<code>v.Interface()</code> to <code>float64</code>; the empty
|
||||
interface value has the concrete value's type information inside
|
||||
and <code>Printf</code> will recover it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In short, the <code>Interface</code> method is the inverse of the
|
||||
<code>ValueOf</code> function, except that its result is always of
|
||||
static type <code>interface{}</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Reiterating: Reflection goes from interface values to reflection
|
||||
objects and back again.
|
||||
</p>
|
||||
|
||||
<p><b>The third law of reflection</b></p>
|
||||
|
||||
<p><b>3. To modify a reflection object, the value must be settable.</b></p>
|
||||
|
||||
<p>
|
||||
The third law is the most subtle and confusing, but it's easy
|
||||
enough to understand if we start from first principles.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here is some code that does not work, but is worth studying.
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f4/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
If you run this code, it will panic with the cryptic message
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
panic: reflect.Value.SetFloat using unaddressable value
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The problem is not that the value <code>7.1</code> is not
|
||||
addressable; it's that <code>v</code> is not settable. Settability
|
||||
is a property of a reflection <code>Value</code>, and not all
|
||||
reflection <code>Values</code> have it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>CanSet</code> method of <code>Value</code> reports the
|
||||
settability of a <code>Value</code>; in our case,
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f5/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
prints
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
settability of v: false
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
It is an error to call a <code>Set</code> method on an non-settable
|
||||
<code>Value</code>. But what is settability?
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Settability is a bit like addressability, but stricter. It's the
|
||||
property that a reflection object can modify the actual storage
|
||||
that was used to create the reflection object. Settability is
|
||||
determined by whether the reflection object holds the original
|
||||
item. When we say
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f6/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
we pass a <em>copy</em> of <code>x</code> to
|
||||
<code>reflect.ValueOf</code>, so the interface value created as the
|
||||
argument to <code>reflect.ValueOf</code> is a <em>copy</em> of
|
||||
<code>x</code>, not <code>x</code> itself. Thus, if the
|
||||
statement
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f6b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
were allowed to succeed, it would not update <code>x</code>, even
|
||||
though <code>v</code> looks like it was created from
|
||||
<code>x</code>. Instead, it would update the copy of <code>x</code>
|
||||
stored inside the reflection value and <code>x</code> itself would
|
||||
be unaffected. That would be confusing and useless, so it is
|
||||
illegal, and settability is the property used to avoid this
|
||||
issue.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If this seems bizarre, it's not. It's actually a familiar situation
|
||||
in unusual garb. Think of passing <code>x</code> to a
|
||||
function:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
f(x)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
We would not expect <code>f</code> to be able to modify
|
||||
<code>x</code> because we passed a copy of <code>x</code>'s value,
|
||||
not <code>x</code> itself. If we want <code>f</code> to modify
|
||||
<code>x</code> directly we must pass our function the address of
|
||||
<code>x</code> (that is, a pointer to <code>x</code>):</p>
|
||||
|
||||
<p>
|
||||
<code>f(&x)</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This is straightforward and familiar, and reflection works the same
|
||||
way. If we want to modify <code>x</code> by reflection, we must
|
||||
give the reflection library a pointer to the value we want to
|
||||
modify.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's do that. First we initialize <code>x</code> as usual
|
||||
and then create a reflection value that points to it, called
|
||||
<code>p</code>.
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f7/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The output so far is
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type of p: *float64
|
||||
settability of p: false
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The reflection object <code>p</code> isn't settable, but it's not
|
||||
<code>p</code> we want to set, it's (in effect) <code>*p</code>. To
|
||||
get to what <code>p</code> points to, we call the <code>Elem</code>
|
||||
method of <code>Value</code>, which indirects through the pointer,
|
||||
and save the result in a reflection <code>Value</code> called
|
||||
<code>v</code>:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f7b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
Now <code>v</code> is a settable reflection object, as the output
|
||||
demonstrates,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
settability of v: true
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
and since it represents <code>x</code>, we are finally able to use
|
||||
<code>v.SetFloat</code> to modify the value of
|
||||
<code>x</code>:
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f7c/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The output, as expected, is
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
7.1
|
||||
7.1
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Reflection can be hard to understand but it's doing exactly what
|
||||
the language does, albeit through reflection <code>Types</code> and
|
||||
<code>Values</code> that can disguise what's going on. Just keep in
|
||||
mind that reflection Values need the address of something in order
|
||||
to modify what they represent.
|
||||
</p>
|
||||
|
||||
<p><b>Structs</b></p>
|
||||
|
||||
<p>
|
||||
In our previous example <code>v</code> wasn't a pointer itself, it
|
||||
was just derived from one. A common way for this situation to arise
|
||||
is when using reflection to modify the fields of a structure. As
|
||||
long as we have the address of the structure, we can modify its
|
||||
fields.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here's a simple example that analyzes a struct value,
|
||||
<code>t</code>. We create the reflection object with the address of
|
||||
the struct because we'll want to modify it later. Then we set
|
||||
<code>typeOfT</code> to its type and iterate over the fields using
|
||||
straightforward method calls (see
|
||||
<a href="http://golang.org/pkg/reflect/">package reflect</a> for details).
|
||||
Note that we extract the names of the fields from the struct type,
|
||||
but the fields themselves are regular <code>reflect.Value</code>
|
||||
objects.
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f8/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
The output of this program is
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
0: A int = 23
|
||||
1: B string = skidoo
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
There's one more point about settability introduced in
|
||||
passing here: the field names of <code>T</code> are upper case
|
||||
(exported) because only exported fields of a struct are
|
||||
settable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Because <code>s</code> contains a settable reflection object, we
|
||||
can modify the fields of the structure.
|
||||
</p>
|
||||
|
||||
{{code "progs/interface2.go" `/START f8b/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
And here's the result:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t is now {77 Sunset Strip}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If we modified the program so that <code>s</code> was created from
|
||||
<code>t</code>, not <code>&t</code>, the calls to
|
||||
<code>SetInt</code> and <code>SetString</code> would fail as the
|
||||
fields of <code>t</code> would not be settable.
|
||||
</p>
|
||||
|
||||
<p><b>Conclusion</b></p>
|
||||
|
||||
<p>
|
||||
Here again are the laws of reflection:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>Reflection goes from interface value to reflection
|
||||
object.</li>
|
||||
<li>Reflection goes from reflection object to interface
|
||||
value.</li>
|
||||
<li>To modify a reflection object, the value must be settable.</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
Once you understand these laws reflection in Go becomes much easier
|
||||
to use, although it remains subtle. It's a powerful tool that
|
||||
should be used with care and avoided unless strictly
|
||||
necessary.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There's plenty more to reflection that we haven't covered —
|
||||
sending and receiving on channels, allocating memory, using slices
|
||||
and maps, calling methods and functions — but this post is
|
||||
long enough. We'll cover some of those topics in a later
|
||||
article.
|
||||
</p>
|
@ -1,11 +1,7 @@
|
||||
<!--{
|
||||
"Title": "Slices: usage and internals"
|
||||
"Title": "Slices: usage and internals",
|
||||
"Template": true
|
||||
}-->
|
||||
<!--
|
||||
DO NOT EDIT: created by
|
||||
tmpltohtml articles/slices_usage_and_internals.tmpl
|
||||
-->
|
||||
|
||||
|
||||
<p>
|
||||
Go's slice type provides a convenient and efficient means of working with
|
||||
@ -326,20 +322,7 @@ appends byte elements to a slice of bytes, growing the slice if necessary, and
|
||||
returns the updated slice value:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/slices.go" `/AppendByte/` `/STOP/`}}
|
||||
-->func AppendByte(slice []byte, data ...byte) []byte {
|
||||
m := len(slice)
|
||||
n := m + len(data)
|
||||
if n > cap(slice) { // if necessary, reallocate
|
||||
// allocate double what's needed, for future growth.
|
||||
newSlice := make([]byte, (n+1)*2)
|
||||
copy(newSlice, slice)
|
||||
slice = newSlice
|
||||
}
|
||||
slice = slice[0:n]
|
||||
copy(slice[m:n], data)
|
||||
return slice
|
||||
}</pre>
|
||||
{{code "/doc/progs/slices.go" `/AppendByte/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
One could use <code>AppendByte</code> like this:
|
||||
@ -398,18 +381,7 @@ Since the zero value of a slice (<code>nil</code>) acts like a zero-length
|
||||
slice, you can declare a slice variable and then append to it in a loop:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/slices.go" `/Filter/` `/STOP/`}}
|
||||
-->// Filter returns a new slice holding only
|
||||
// the elements of s that satisfy f()
|
||||
func Filter(s []int, fn func(int) bool) []int {
|
||||
var p []int // == nil
|
||||
for _, i := range s {
|
||||
if fn(i) {
|
||||
p = append(p, i)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}</pre>
|
||||
{{code "/doc/progs/slices.go" `/Filter/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
<b>A possible "gotcha"</b>
|
||||
@ -428,13 +400,7 @@ searches it for the first group of consecutive numeric digits, returning them
|
||||
as a new slice.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/slices.go" `/digit/` `/STOP/`}}
|
||||
-->var digitRegexp = regexp.MustCompile("[0-9]+")
|
||||
|
||||
func FindDigits(filename string) []byte {
|
||||
b, _ := ioutil.ReadFile(filename)
|
||||
return digitRegexp.Find(b)
|
||||
}</pre>
|
||||
{{code "/doc/progs/slices.go" `/digit/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This code behaves as advertised, but the returned <code>[]byte</code> points
|
||||
@ -449,14 +415,7 @@ To fix this problem one can copy the interesting data to a new slice before
|
||||
returning it:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/slices.go" `/CopyDigits/` `/STOP/`}}
|
||||
-->func CopyDigits(filename string) []byte {
|
||||
b, _ := ioutil.ReadFile(filename)
|
||||
b = digitRegexp.Find(b)
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}</pre>
|
||||
{{code "/doc/progs/slices.go" `/CopyDigits/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
A more concise version of this function could be constructed by using
|
||||
|
@ -1,438 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Slices: usage and internals"
|
||||
}-->
|
||||
{{donotedit}}
|
||||
|
||||
<p>
|
||||
Go's slice type provides a convenient and efficient means of working with
|
||||
sequences of typed data. Slices are analogous to arrays in other languages, but
|
||||
have some unusual properties. This article will look at what slices are and how
|
||||
they are used.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Arrays</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The slice type is an abstraction built on top of Go's array type, and so to
|
||||
understand slices we must first understand arrays.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An array type definition specifies a length and an element type. For example,
|
||||
the type <code>[4]int</code> represents an array of four integers. An array's
|
||||
size is fixed; its length is part of its type (<code>[4]int</code> and
|
||||
<code>[5]int</code> are distinct, incompatible types). Arrays can be indexed in
|
||||
the usual way, so the expression <code>s[n]</code> accesses the <i>n</i>th
|
||||
element:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a [4]int
|
||||
a[0] = 1
|
||||
i := a[0]
|
||||
// i == 1
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Arrays do not need to be initialized explicitly; the zero value of an array is
|
||||
a ready-to-use array whose elements are themselves zeroed:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// a[2] == 0, the zero value of the int type
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The in-memory representation of <code>[4]int</code> is just four integer values laid out sequentially:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="slice-array.png">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go's arrays are values. An array variable denotes the entire array; it is not a
|
||||
pointer to the first array element (as would be the case in C). This means
|
||||
that when you assign or pass around an array value you will make a copy of its
|
||||
contents. (To avoid the copy you could pass a <i>pointer</i> to the array, but
|
||||
then that's a pointer to an array, not an array.) One way to think about arrays
|
||||
is as a sort of struct but with indexed rather than named fields: a fixed-size
|
||||
composite value.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An array literal can be specified like so:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
b := [2]string{"Penn", "Teller"}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Or, you can have the compiler count the array elements for you:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
b := [...]string{"Penn", "Teller"}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In both cases, the type of <code>b</code> is <code>[2]string</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Slices</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Arrays have their place, but they're a bit inflexible, so you don't see them
|
||||
too often in Go code. Slices, though, are everywhere. They build on arrays to
|
||||
provide great power and convenience.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The type specification for a slice is <code>[]T</code>, where <code>T</code> is
|
||||
the type of the elements of the slice. Unlike an array type, a slice type has
|
||||
no specified length.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A slice literal is declared just like an array literal, except you leave out
|
||||
the element count:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
letters := []string{"a", "b", "c", "d"}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A slice can be created with the built-in function called <code>make</code>,
|
||||
which has the signature,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func make([]T, len, cap) []T
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
where T stands for the element type of the slice to be created. The
|
||||
<code>make</code> function takes a type, a length, and an optional capacity.
|
||||
When called, <code>make</code> allocates an array and returns a slice that
|
||||
refers to that array.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var s []byte
|
||||
s = make([]byte, 5, 5)
|
||||
// s == []byte{0, 0, 0, 0, 0}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
When the capacity argument is omitted, it defaults to the specified length.
|
||||
Here's a more succinct version of the same code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
s := make([]byte, 5)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The length and capacity of a slice can be inspected using the built-in
|
||||
<code>len</code> and <code>cap</code> functions.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
len(s) == 5
|
||||
cap(s) == 5
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The next two sections discuss the relationship between length and capacity.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The zero value of a slice is <code>nil</code>. The <code>len</code> and
|
||||
<code>cap</code> functions will both return 0 for a nil slice.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A slice can also be formed by "slicing" an existing slice or array. Slicing is
|
||||
done by specifying a half-open range with two indices separated by a colon. For
|
||||
example, the expression <code>b[1:4]</code> creates a slice including elements
|
||||
1 through 3 of <code>b</code> (the indices of the resulting slice will be 0
|
||||
through 2).
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
|
||||
// b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The start and end indices of a slice expression are optional; they default to zero and the slice's length respectively:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// b[:2] == []byte{'g', 'o'}
|
||||
// b[2:] == []byte{'l', 'a', 'n', 'g'}
|
||||
// b[:] == b
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This is also the syntax to create a slice given an array:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
x := [3]string{"Лайка", "Белка", "Стрелка"}
|
||||
s := x[:] // a slice referencing the storage of x
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<b>Slice internals</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A slice is a descriptor of an array segment. It consists of a pointer to the
|
||||
array, the length of the segment, and its capacity (the maximum length of the
|
||||
segment).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="slice-struct.png">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Our variable <code>s</code>, created earlier by <code>make([]byte, 5)</code>,
|
||||
is structured like this:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="slice-1.png">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The length is the number of elements referred to by the slice. The capacity is
|
||||
the number of elements in the underlying array (beginning at the element
|
||||
referred to by the slice pointer). The distinction between length and capacity
|
||||
will be made clear as we walk through the next few examples.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As we slice <code>s</code>, observe the changes in the slice data structure and
|
||||
their relation to the underlying array:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
s = s[2:4]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<img src="slice-2.png">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Slicing does not copy the slice's data. It creates a new slice value that
|
||||
points to the original array. This makes slice operations as efficient as
|
||||
manipulating array indices. Therefore, modifying the <i>elements</i> (not the
|
||||
slice itself) of a re-slice modifies the elements of the original slice:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
d := []byte{'r', 'o', 'a', 'd'}
|
||||
e := d[2:]
|
||||
// e == []byte{'a', 'd'}
|
||||
e[1] == 'm'
|
||||
// e == []byte{'a', 'm'}
|
||||
// d == []byte{'r', 'o', 'a', 'm'}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Earlier we sliced <code>s</code> to a length shorter than its capacity. We can
|
||||
grow s to its capacity by slicing it again:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
s = s[:cap(s)]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<img src="slice-3.png">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A slice cannot be grown beyond its capacity. Attempting to do so will cause a
|
||||
runtime panic, just as when indexing outside the bounds of a slice or array.
|
||||
Similarly, slices cannot be re-sliced below zero to access earlier elements in
|
||||
the array.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Growing slices (the copy and append functions)</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To increase the capacity of a slice one must create a new, larger slice and
|
||||
copy the contents of the original slice into it. This technique is how dynamic
|
||||
array implementations from other languages work behind the scenes. The next
|
||||
example doubles the capacity of <code>s</code> by making a new slice,
|
||||
<code>t</code>, copying the contents of <code>s</code> into <code>t</code>, and
|
||||
then assigning the slice value <code>t</code> to <code>s</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
|
||||
for i := range s {
|
||||
t[i] = s[i]
|
||||
}
|
||||
s = t
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The looping piece of this common operation is made easier by the built-in copy
|
||||
function. As the name suggests, copy copies data from a source slice to a
|
||||
destination slice. It returns the number of elements copied.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func copy(dst, src []T) int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>copy</code> function supports copying between slices of different
|
||||
lengths (it will copy only up to the smaller number of elements). In addition,
|
||||
<code>copy</code> can handle source and destination slices that share the same
|
||||
underlying array, handling overlapping slices correctly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Using <code>copy</code>, we can simplify the code snippet above:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t := make([]byte, len(s), (cap(s)+1)*2)
|
||||
copy(t, s)
|
||||
s = t
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A common operation is to append data to the end of a slice. This function
|
||||
appends byte elements to a slice of bytes, growing the slice if necessary, and
|
||||
returns the updated slice value:
|
||||
</p>
|
||||
|
||||
{{code "progs/slices.go" `/AppendByte/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
One could use <code>AppendByte</code> like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
p := []byte{2, 3, 5}
|
||||
p = AppendByte(p, 7, 11, 13)
|
||||
// p == []byte{2, 3, 5, 7, 11, 13}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Functions like <code>AppendByte</code> are useful because they offer complete
|
||||
control over the way the slice is grown. Depending on the characteristics of
|
||||
the program, it may be desirable to allocate in smaller or larger chunks, or to
|
||||
put a ceiling on the size of a reallocation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
But most programs don't need complete control, so Go provides a built-in
|
||||
<code>append</code> function that's good for most purposes; it has the
|
||||
signature
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func append(s []T, x ...T) []T
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>append</code> function appends the elements <code>x</code> to the end
|
||||
of the slice <code>s</code>, and grows the slice if a greater capacity is
|
||||
needed.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
a := make([]int, 1)
|
||||
// a == []int{0}
|
||||
a = append(a, 1, 2, 3)
|
||||
// a == []int{0, 1, 2, 3}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To append one slice to another, use <code>...</code> to expand the second
|
||||
argument to a list of arguments.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
a := []string{"John", "Paul"}
|
||||
b := []string{"George", "Ringo", "Pete"}
|
||||
a = append(a, b...) // equivalent to "append(a, b[0], b[1], b[2])"
|
||||
// a == []string{"John", "Paul", "George", "Ringo", "Pete"}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Since the zero value of a slice (<code>nil</code>) acts like a zero-length
|
||||
slice, you can declare a slice variable and then append to it in a loop:
|
||||
</p>
|
||||
|
||||
{{code "progs/slices.go" `/Filter/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
<b>A possible "gotcha"</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As mentioned earlier, re-slicing a slice doesn't make a copy of the underlying
|
||||
array. The full array will be kept in memory until it is no longer referenced.
|
||||
Occasionally this can cause the program to hold all the data in memory when
|
||||
only a small piece of it is needed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, this <code>FindDigits</code> function loads a file into memory and
|
||||
searches it for the first group of consecutive numeric digits, returning them
|
||||
as a new slice.
|
||||
</p>
|
||||
|
||||
{{code "progs/slices.go" `/digit/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
This code behaves as advertised, but the returned <code>[]byte</code> points
|
||||
into an array containing the entire file. Since the slice references the
|
||||
original array, as long as the slice is kept around the garbage collector can't
|
||||
release the array; the few useful bytes of the file keep the entire contents in
|
||||
memory.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To fix this problem one can copy the interesting data to a new slice before
|
||||
returning it:
|
||||
</p>
|
||||
|
||||
{{code "progs/slices.go" `/CopyDigits/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
A more concise version of this function could be constructed by using
|
||||
<code>append</code>. This is left as an exercise for the reader.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Further Reading</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/doc/effective_go.html">Effective Go</a> contains an
|
||||
in-depth treatment of <a href="/doc/effective_go.html#slices">slices</a>
|
||||
and <a href="/doc/effective_go.html#arrays">arrays</a>,
|
||||
and the Go <a href="/doc/go_spec.html">language specification</a>
|
||||
defines <a href="/doc/go_spec.html#Slice_types">slices</a> and their
|
||||
<a href="/doc/go_spec.html#Length_and_capacity">associated</a>
|
||||
<a href="/doc/go_spec.html#Making_slices_maps_and_channels">helper</a>
|
||||
<a href="/doc/go_spec.html#Appending_and_copying_slices">functions</a>.
|
||||
</p>
|
@ -1,11 +1,7 @@
|
||||
<!--{
|
||||
"Title": "Effective Go"
|
||||
"Title": "Effective Go",
|
||||
"Template": true
|
||||
}-->
|
||||
<!--
|
||||
DO NOT EDIT: created by
|
||||
tmpltohtml effective_go.tmpl
|
||||
-->
|
||||
|
||||
|
||||
<h2 id="introduction">Introduction</h2>
|
||||
|
||||
@ -1693,47 +1689,13 @@ enumerator. Since <code>iota</code> can be part of an expression and
|
||||
expressions can be implicitly repeated, it is easy to build intricate
|
||||
sets of values.
|
||||
</p>
|
||||
<pre><!--{{code "progs/eff_bytesize.go" `/^type ByteSize/` `/^\)/`}}
|
||||
-->type ByteSize float64
|
||||
|
||||
const (
|
||||
_ = iota // ignore first value by assigning to blank identifier
|
||||
KB ByteSize = 1 << (10 * iota)
|
||||
MB
|
||||
GB
|
||||
TB
|
||||
PB
|
||||
EB
|
||||
ZB
|
||||
YB
|
||||
)</pre>
|
||||
{{code "/doc/progs/eff_bytesize.go" `/^type ByteSize/` `/^\)/`}}
|
||||
<p>
|
||||
The ability to attach a method such as <code>String</code> to a
|
||||
type makes it possible for such values to format themselves
|
||||
automatically for printing, even as part of a general type.
|
||||
</p>
|
||||
<pre><!--{{code "progs/eff_bytesize.go" `/^func.*ByteSize.*String/` `/^}/`}}
|
||||
-->func (b ByteSize) String() string {
|
||||
switch {
|
||||
case b >= YB:
|
||||
return fmt.Sprintf("%.2fYB", float64(b/YB))
|
||||
case b >= ZB:
|
||||
return fmt.Sprintf("%.2fZB", float64(b/ZB))
|
||||
case b >= EB:
|
||||
return fmt.Sprintf("%.2fEB", float64(b/EB))
|
||||
case b >= PB:
|
||||
return fmt.Sprintf("%.2fPB", float64(b/PB))
|
||||
case b >= TB:
|
||||
return fmt.Sprintf("%.2fTB", float64(b/TB))
|
||||
case b >= GB:
|
||||
return fmt.Sprintf("%.2fGB", float64(b/GB))
|
||||
case b >= MB:
|
||||
return fmt.Sprintf("%.2fMB", float64(b/MB))
|
||||
case b >= KB:
|
||||
return fmt.Sprintf("%.2fKB", float64(b/KB))
|
||||
}
|
||||
return fmt.Sprintf("%.2fB", float64(b))
|
||||
}</pre>
|
||||
{{code "/doc/progs/eff_bytesize.go" `/^func.*ByteSize.*String/` `/^}/`}}
|
||||
<p>
|
||||
(The <code>float64</code> conversions prevent <code>Sprintf</code>
|
||||
from recurring back through the <code>String</code> method for
|
||||
@ -1879,32 +1841,7 @@ by the routines in package <code>sort</code> if it implements
|
||||
and it could also have a custom formatter.
|
||||
In this contrived example <code>Sequence</code> satisfies both.
|
||||
</p>
|
||||
<pre><!--{{code "progs/eff_sequence.go" `/^type/` "$"}}
|
||||
-->type Sequence []int
|
||||
|
||||
// Methods required by sort.Interface.
|
||||
func (s Sequence) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s Sequence) Less(i, j int) bool {
|
||||
return s[i] < s[j]
|
||||
}
|
||||
func (s Sequence) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// Method for printing - sorts the elements before printing.
|
||||
func (s Sequence) String() string {
|
||||
sort.Sort(s)
|
||||
str := "["
|
||||
for i, elem := range s {
|
||||
if i > 0 {
|
||||
str += " "
|
||||
}
|
||||
str += fmt.Sprint(elem)
|
||||
}
|
||||
return str + "]"
|
||||
}</pre>
|
||||
{{code "/doc/progs/eff_sequence.go" `/^type/` "$"}}
|
||||
|
||||
<h3 id="conversions">Conversions</h3>
|
||||
|
||||
@ -3010,53 +2947,7 @@ for instance, a URL, saving you typing the URL into the phone's tiny keyboard.
|
||||
Here's the complete program.
|
||||
An explanation follows.
|
||||
</p>
|
||||
<pre><!--{{code "progs/eff_qr.go"}}
|
||||
-->package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
|
||||
|
||||
var templ = template.Must(template.New("qr").Parse(templateStr))
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
http.Handle("/", http.HandlerFunc(QR))
|
||||
err := http.ListenAndServe(*addr, nil)
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func QR(w http.ResponseWriter, req *http.Request) {
|
||||
templ.Execute(w, req.FormValue("s"))
|
||||
}
|
||||
|
||||
const templateStr = `
|
||||
<html>
|
||||
<head>
|
||||
<title>QR Link Generator</title>
|
||||
</head>
|
||||
<body>
|
||||
{{if .}}
|
||||
<img src="http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=UTF-8&chl={{urlquery .}}" />
|
||||
<br>
|
||||
{{html .}}
|
||||
<br>
|
||||
<br>
|
||||
{{end}}
|
||||
<form action="/" name=f method="GET"><input maxLength=1024 size=70
|
||||
name=s value="" title="Text to QR Encode"><input type=submit
|
||||
value="Show QR" name=qr>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`</pre>
|
||||
{{code "/doc/progs/eff_qr.go"}}
|
||||
<p>
|
||||
The pieces up to <code>main</code> should be easy to follow.
|
||||
The one flag sets a default HTTP port for our server. The template
|
||||
@ -3082,13 +2973,13 @@ from data items passed to <code>templ.Execute</code>, in this case the
|
||||
form value.
|
||||
Within the template text (<code>templateStr</code>),
|
||||
double-brace-delimited pieces denote template actions.
|
||||
The piece from <code>{{if .}}</code>
|
||||
to <code>{{end}}</code> executes only if the value of the current data item, called <code>.</code> (dot),
|
||||
The piece from <code>{{html "{{if .}}"}}</code>
|
||||
to <code>{{html "{{end}}"}}</code> executes only if the value of the current data item, called <code>.</code> (dot),
|
||||
is non-empty.
|
||||
That is, when the string is empty, this piece of the template is suppressed.
|
||||
</p>
|
||||
<p>
|
||||
The snippet <code>{{urlquery .}}</code> says to process the data with the function
|
||||
The snippet <code>{{html "{{urlquery .}}"}}</code> says to process the data with the function
|
||||
<code>urlquery</code>, which sanitizes the query string
|
||||
for safe display on the web page.
|
||||
</p>
|
||||
|
File diff suppressed because it is too large
Load Diff
164
doc/go1.html
164
doc/go1.html
@ -1,11 +1,7 @@
|
||||
<!--{
|
||||
"Title": "Go 1 Release Notes"
|
||||
"Title": "Go 1 Release Notes",
|
||||
"Template": true
|
||||
}-->
|
||||
<!--
|
||||
DO NOT EDIT: created by
|
||||
tmpltohtml go1.tmpl
|
||||
-->
|
||||
|
||||
|
||||
<h2 id="introduction">Introduction to Go 1</h2>
|
||||
|
||||
@ -64,9 +60,7 @@ However, <code>append</code> did not provide a way to append a string to a <code
|
||||
which is another common case.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/greeting := ..byte/` `/append.*hello/`}}
|
||||
--> greeting := []byte{}
|
||||
greeting = append(greeting, []byte("hello ")...)</pre>
|
||||
{{code "/doc/progs/go1.go" `/greeting := ..byte/` `/append.*hello/`}}
|
||||
|
||||
<p>
|
||||
By analogy with the similar property of <code>copy</code>, Go 1
|
||||
@ -75,8 +69,7 @@ slice, reducing the friction between strings and byte slices.
|
||||
The conversion is no longer necessary:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/append.*world/`}}
|
||||
--> greeting = append(greeting, "world"...)</pre>
|
||||
{{code "/doc/progs/go1.go" `/append.*world/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -126,35 +119,7 @@ type specification for the elements' initializers if they are of pointer type.
|
||||
All four of the initializations in this example are legal; the last one was illegal before Go 1.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/type Date struct/` `/STOP/`}}
|
||||
--> type Date struct {
|
||||
month string
|
||||
day int
|
||||
}
|
||||
// Struct values, fully qualified; always legal.
|
||||
holiday1 := []Date{
|
||||
Date{"Feb", 14},
|
||||
Date{"Nov", 11},
|
||||
Date{"Dec", 25},
|
||||
}
|
||||
// Struct values, type name elided; always legal.
|
||||
holiday2 := []Date{
|
||||
{"Feb", 14},
|
||||
{"Nov", 11},
|
||||
{"Dec", 25},
|
||||
}
|
||||
// Pointers, fully qualified, always legal.
|
||||
holiday3 := []*Date{
|
||||
&Date{"Feb", 14},
|
||||
&Date{"Nov", 11},
|
||||
&Date{"Dec", 25},
|
||||
}
|
||||
// Pointers, type name elided; legal in Go 1.
|
||||
holiday4 := []*Date{
|
||||
{"Feb", 14},
|
||||
{"Nov", 11},
|
||||
{"Dec", 25},
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/type Date struct/` `/STOP/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -183,14 +148,7 @@ In Go 1, code that uses goroutines can be called from
|
||||
without introducing a deadlock.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/PackageGlobal/` `/^}/`}}
|
||||
-->var PackageGlobal int
|
||||
|
||||
func init() {
|
||||
c := make(chan int)
|
||||
go initializationFunction(c)
|
||||
PackageGlobal = <-c
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/PackageGlobal/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -231,14 +189,7 @@ when appropriate. For instance, the functions <code>unicode.ToLower</code> and
|
||||
relatives now take and return a <code>rune</code>.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/STARTRUNE/` `/ENDRUNE/`}}
|
||||
--> delta := 'δ' // delta has type rune.
|
||||
var DELTA rune
|
||||
DELTA = unicode.ToUpper(delta)
|
||||
epsilon := unicode.ToLower(DELTA + 1)
|
||||
if epsilon != 'δ'+1 {
|
||||
log.Fatal("inconsistent casing for Greek")
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/STARTRUNE/` `/ENDRUNE/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -287,8 +238,7 @@ In Go 1, that syntax has gone; instead there is a new built-in
|
||||
function, <code>delete</code>. The call
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/delete\(m, k\)/`}}
|
||||
--> delete(m, k)</pre>
|
||||
{{code "/doc/progs/go1.go" `/delete\(m, k\)/`}}
|
||||
|
||||
<p>
|
||||
will delete the map entry retrieved by the expression <code>m[k]</code>.
|
||||
@ -327,12 +277,7 @@ This change means that code that depends on iteration order is very likely to br
|
||||
Just as important, it allows the map implementation to ensure better map balancing even when programs are using range loops to select an element from a map.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/Sunday/` `/^ }/`}}
|
||||
--> m := map[string]int{"Sunday": 0, "Monday": 1}
|
||||
for name, value := range m {
|
||||
// This loop should not assume Sunday will be visited first.
|
||||
f(name, value)
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/Sunday/` `/^ }/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -367,17 +312,7 @@ proceed in left-to-right order.
|
||||
These examples illustrate the behavior.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/sa :=/` `/then sc.0. = 2/`}}
|
||||
--> sa := []int{1, 2, 3}
|
||||
i := 0
|
||||
i, sa[i] = 1, 2 // sets i = 1, sa[0] = 2
|
||||
|
||||
sb := []int{1, 2, 3}
|
||||
j := 0
|
||||
sb[j], j = 2, 1 // sets sb[0] = 2, j = 1
|
||||
|
||||
sc := []int{1, 2, 3}
|
||||
sc[0], sc[0] = 1, 2 // sets sc[0] = 1, then sc[0] = 2 (so sc[0] = 2 at end)</pre>
|
||||
{{code "/doc/progs/go1.go" `/sa :=/` `/then sc.0. = 2/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -504,18 +439,7 @@ provided they are composed from elements for which equality is also defined,
|
||||
using element-wise comparison.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/type Day struct/` `/Printf/`}}
|
||||
--> type Day struct {
|
||||
long string
|
||||
short string
|
||||
}
|
||||
Christmas := Day{"Christmas", "XMas"}
|
||||
Thanksgiving := Day{"Thanksgiving", "Turkey"}
|
||||
holiday := map[Day]bool{
|
||||
Christmas: true,
|
||||
Thanksgiving: true,
|
||||
}
|
||||
fmt.Printf("Christmas is a holiday: %t\n", holiday[Christmas])</pre>
|
||||
{{code "/doc/progs/go1.go" `/type Day struct/` `/Printf/`}}
|
||||
|
||||
<p>
|
||||
Second, Go 1 removes the definition of equality for function values,
|
||||
@ -831,16 +755,7 @@ The <code>fmt</code> library automatically invokes <code>Error</code>, as it alr
|
||||
does for <code>String</code>, for easy printing of error values.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/START ERROR EXAMPLE/` `/END ERROR EXAMPLE/`}}
|
||||
-->type SyntaxError struct {
|
||||
File string
|
||||
Line int
|
||||
Message string
|
||||
}
|
||||
|
||||
func (se *SyntaxError) Error() string {
|
||||
return fmt.Sprintf("%s:%d: %s", se.File, se.Line, se.Message)
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/START ERROR EXAMPLE/` `/END ERROR EXAMPLE/`}}
|
||||
|
||||
<p>
|
||||
All standard packages have been updated to use the new interface; the old <code>os.Error</code> is gone.
|
||||
@ -858,8 +773,7 @@ func New(text string) error
|
||||
to turn a string into an error. It replaces the old <code>os.NewError</code>.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/ErrSyntax/`}}
|
||||
--> var ErrSyntax = errors.New("syntax error")</pre>
|
||||
{{code "/doc/progs/go1.go" `/ErrSyntax/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -949,17 +863,7 @@ returns a <code>time.Time</code> value rather than, in the old
|
||||
API, an integer nanosecond count since the Unix epoch.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/sleepUntil/` `/^}/`}}
|
||||
-->// sleepUntil sleeps until the specified time. It returns immediately if it's too late.
|
||||
func sleepUntil(wakeup time.Time) {
|
||||
now := time.Now() // A Time.
|
||||
if !wakeup.After(now) {
|
||||
return
|
||||
}
|
||||
delta := wakeup.Sub(now) // A Duration.
|
||||
fmt.Printf("Sleeping for %.3fs\n", delta.Seconds())
|
||||
time.Sleep(delta)
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/sleepUntil/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
The new types, methods, and constants have been propagated through
|
||||
@ -1196,8 +1100,7 @@ Values for such flags must be given units, just as <code>time.Duration</code>
|
||||
formats them: <code>10s</code>, <code>1h30m</code>, etc.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/timeout/`}}
|
||||
-->var timeout = flag.Duration("timeout", 30*time.Second, "how long to wait for completion")</pre>
|
||||
{{code "/doc/progs/go1.go" `/timeout/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -1711,11 +1614,7 @@ and
|
||||
<a href="/pkg/os/#IsPermission"><code>IsPermission</code></a>.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/os\.Open/` `/}/`}}
|
||||
--> f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
|
||||
if os.IsExist(err) {
|
||||
log.Printf("%s already exists", name)
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/os\.Open/` `/}/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -1781,21 +1680,7 @@ If a directory's contents are to be skipped,
|
||||
the function should return the value <a href="/pkg/path/filepath/#variables"><code>filepath.SkipDir</code></a>
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/STARTWALK/` `/ENDWALK/`}}
|
||||
--> markFn := func(path string, info os.FileInfo, err error) error {
|
||||
if path == "pictures" { // Will skip walking of directory pictures and its contents.
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println(path)
|
||||
return nil
|
||||
}
|
||||
err := filepath.Walk(".", markFn)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/STARTWALK/` `/ENDWALK/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
@ -1993,20 +1878,7 @@ In Go 1, <code>B</code> has new methods, analogous to those of <code>T</code>, e
|
||||
logging and failure reporting.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/func.*Benchmark/` `/^}/`}}
|
||||
-->func BenchmarkSprintf(b *testing.B) {
|
||||
// Verify correctness before running benchmark.
|
||||
b.StopTimer()
|
||||
got := fmt.Sprintf("%x", 23)
|
||||
const expect = "17"
|
||||
if expect != got {
|
||||
b.Fatalf("expected %q; got %q", expect, got)
|
||||
}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Sprintf("%x", 23)
|
||||
}
|
||||
}</pre>
|
||||
{{code "/doc/progs/go1.go" `/func.*Benchmark/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
|
2029
doc/go1.tmpl
2029
doc/go1.tmpl
File diff suppressed because it is too large
Load Diff
@ -87,6 +87,9 @@ The flags are:
|
||||
directory containing alternate template files; if set,
|
||||
the directory may provide alternative template files
|
||||
for the files in $GOROOT/lib/godoc
|
||||
-url=path
|
||||
print to standard output the data that would be served by
|
||||
an HTTP request for path
|
||||
-zip=""
|
||||
zip file providing the file system to serve; disabled if empty
|
||||
|
||||
|
@ -605,6 +605,23 @@ func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
|
||||
log.Printf("decoding metadata %s: %v", relpath, err)
|
||||
}
|
||||
|
||||
// evaluate as template if indicated
|
||||
if meta.Template {
|
||||
tmpl, err := template.New("main").Funcs(templateFuncs).Parse(string(src))
|
||||
if err != nil {
|
||||
log.Printf("parsing template %s: %v", relpath, err)
|
||||
serveError(w, r, relpath, err)
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.Execute(&buf, nil); err != nil {
|
||||
log.Printf("executing template %s: %v", relpath, err)
|
||||
serveError(w, r, relpath, err)
|
||||
return
|
||||
}
|
||||
src = buf.Bytes()
|
||||
}
|
||||
|
||||
// if it's the language spec, add tags to EBNF productions
|
||||
if strings.HasSuffix(abspath, "go_spec.html") {
|
||||
var buf bytes.Buffer
|
||||
@ -1177,6 +1194,7 @@ func search(w http.ResponseWriter, r *http.Request) {
|
||||
type Metadata struct {
|
||||
Title string
|
||||
Subtitle string
|
||||
Template bool // execute as template
|
||||
Path string // canonical path for this page
|
||||
filePath string // filesystem path relative to goroot
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
_ "net/http/pprof" // to serve /debug/pprof/*
|
||||
"net/url"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
@ -69,6 +70,7 @@ var (
|
||||
// layout control
|
||||
html = flag.Bool("html", false, "print HTML in command-line mode")
|
||||
srcMode = flag.Bool("src", false, "print (exported) source in command-line mode")
|
||||
urlFlag = flag.String("url", "", "print HTML for named URL")
|
||||
|
||||
// command-line searches
|
||||
query = flag.Bool("q", false, "arguments are considered search queries")
|
||||
@ -225,7 +227,7 @@ func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Check usage: either server and no args, command line and args, or index creation mode
|
||||
if (*httpAddr != "") != (flag.NArg() == 0) && !*writeIndex {
|
||||
if (*httpAddr != "" || *urlFlag != "") != (flag.NArg() == 0) && !*writeIndex {
|
||||
usage()
|
||||
}
|
||||
|
||||
@ -286,6 +288,44 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// Print content that would be served at the URL *urlFlag.
|
||||
if *urlFlag != "" {
|
||||
registerPublicHandlers(http.DefaultServeMux)
|
||||
// Try up to 10 fetches, following redirects.
|
||||
urlstr := *urlFlag
|
||||
for i := 0; i < 10; i++ {
|
||||
// Prepare request.
|
||||
u, err := url.Parse(urlstr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
req := &http.Request{
|
||||
URL: u,
|
||||
}
|
||||
|
||||
// Invoke default HTTP handler to serve request
|
||||
// to our buffering httpWriter.
|
||||
w := &httpWriter{h: http.Header{}, code: 200}
|
||||
http.DefaultServeMux.ServeHTTP(w, req)
|
||||
|
||||
// Return data, error, or follow redirect.
|
||||
switch w.code {
|
||||
case 200: // ok
|
||||
os.Stdout.Write(w.Bytes())
|
||||
return
|
||||
case 301, 302, 303, 307: // redirect
|
||||
redirect := w.h.Get("Location")
|
||||
if redirect == "" {
|
||||
log.Fatalf("HTTP %d without Location header", w.code)
|
||||
}
|
||||
urlstr = redirect
|
||||
default:
|
||||
log.Fatalf("HTTP error %d", w.code)
|
||||
}
|
||||
}
|
||||
log.Fatalf("too many redirects")
|
||||
}
|
||||
|
||||
if *httpAddr != "" {
|
||||
// HTTP server mode.
|
||||
var handler http.Handler = http.DefaultServeMux
|
||||
@ -494,3 +534,13 @@ func main() {
|
||||
log.Printf("packageText.Execute: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// An httpWriter is an http.ResponseWriter writing to a bytes.Buffer.
|
||||
type httpWriter struct {
|
||||
bytes.Buffer
|
||||
h http.Header
|
||||
code int
|
||||
}
|
||||
|
||||
func (w *httpWriter) Header() http.Header { return w.h }
|
||||
func (w *httpWriter) WriteHeader(code int) { w.code = code }
|
||||
|
@ -2,6 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Template support for writing HTML documents.
|
||||
// Documents that include Template: true in their
|
||||
// metadata are executed as input to text/template.
|
||||
//
|
||||
// This file defines functions for those templates to invoke.
|
||||
|
||||
// The template uses the function "code" to inject program
|
||||
// source into the output by extracting code from files and
|
||||
// injecting them as HTML-escaped <pre> blocks.
|
||||
@ -26,52 +32,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func Usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: tmpltohtml file\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
// Functions in this file panic on error, but the panic is recovered
|
||||
// to an error by 'code'.
|
||||
|
||||
var templateFuncs = template.FuncMap{
|
||||
"code": code,
|
||||
"donotedit": donotedit,
|
||||
"code": code,
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = Usage
|
||||
flag.Parse()
|
||||
if len(flag.Args()) != 1 {
|
||||
Usage()
|
||||
}
|
||||
|
||||
// Read and parse the input.
|
||||
name := flag.Arg(0)
|
||||
tmpl := template.New(filepath.Base(name)).Funcs(templateFuncs)
|
||||
if _, err := tmpl.ParseFiles(name); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Execute the template.
|
||||
if err := tmpl.Execute(os.Stdout, 0); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// contents reads a file by name and returns its contents as a string.
|
||||
// contents reads and returns the content of the named file
|
||||
// (from the virtual file system, so for example /doc refers to $GOROOT/doc).
|
||||
func contents(name string) string {
|
||||
file, err := ioutil.ReadFile(name)
|
||||
file, err := ReadFile(fs, name)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panic(err)
|
||||
}
|
||||
return string(file)
|
||||
}
|
||||
@ -87,17 +67,18 @@ func format(arg interface{}) string {
|
||||
}
|
||||
return fmt.Sprintf("%q", arg)
|
||||
default:
|
||||
log.Fatalf("unrecognized argument: %v type %T", arg, arg)
|
||||
log.Panicf("unrecognized argument: %v type %T", arg, arg)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func donotedit() string {
|
||||
// No editing please.
|
||||
return fmt.Sprintf("<!--\n DO NOT EDIT: created by\n tmpltohtml %s\n-->\n", flag.Args()[0])
|
||||
}
|
||||
func code(file string, arg ...interface{}) (s string, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
func code(file string, arg ...interface{}) (string, error) {
|
||||
text := contents(file)
|
||||
var command string
|
||||
switch len(arg) {
|
||||
@ -129,13 +110,13 @@ func parseArg(arg interface{}, file string, max int) (ival int, sval string, isI
|
||||
switch n := arg.(type) {
|
||||
case int:
|
||||
if n <= 0 || n > max {
|
||||
log.Fatalf("%q:%d is out of range", file, n)
|
||||
log.Panicf("%q:%d is out of range", file, n)
|
||||
}
|
||||
return n, "", true
|
||||
case string:
|
||||
return 0, n, false
|
||||
}
|
||||
log.Fatalf("unrecognized argument %v type %T", arg, arg)
|
||||
log.Panicf("unrecognized argument %v type %T", arg, arg)
|
||||
return
|
||||
}
|
||||
|
||||
@ -160,7 +141,7 @@ func multipleLines(file, text string, arg1, arg2 interface{}) string {
|
||||
if !isInt2 {
|
||||
line2 = match(file, line1, lines, pattern2)
|
||||
} else if line2 < line1 {
|
||||
log.Fatalf("lines out of order for %q: %d %d", text, line1, line2)
|
||||
log.Panicf("lines out of order for %q: %d %d", text, line1, line2)
|
||||
}
|
||||
for k := line1 - 1; k < line2; k++ {
|
||||
if strings.HasSuffix(lines[k], "OMIT\n") {
|
||||
@ -177,7 +158,7 @@ func match(file string, start int, lines []string, pattern string) int {
|
||||
// $ matches the end of the file.
|
||||
if pattern == "$" {
|
||||
if len(lines) == 0 {
|
||||
log.Fatalf("%q: empty file", file)
|
||||
log.Panicf("%q: empty file", file)
|
||||
}
|
||||
return len(lines)
|
||||
}
|
||||
@ -185,15 +166,15 @@ func match(file string, start int, lines []string, pattern string) int {
|
||||
if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
|
||||
re, err := regexp.Compile(pattern[1 : len(pattern)-1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Panic(err)
|
||||
}
|
||||
for i := start; i < len(lines); i++ {
|
||||
if re.MatchString(lines[i]) {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
log.Fatalf("%s: no match for %#q", file, pattern)
|
||||
log.Panicf("%s: no match for %#q", file, pattern)
|
||||
}
|
||||
log.Fatalf("unrecognized pattern: %q", pattern)
|
||||
log.Panicf("unrecognized pattern: %q", pattern)
|
||||
return 0
|
||||
}
|
Loading…
Reference in New Issue
Block a user