mirror of
https://github.com/golang/go
synced 2024-11-22 04:14:42 -07:00
doc: trim spaces from code snippets
gofmt likes to put lines like // STOP OMIT two blank lines from a closing brace, creating an ugly space inside <pre> blocks in some of these files. This change resolves this issue. R=golang-dev, iant CC=golang-dev https://golang.org/cl/5520044
This commit is contained in:
parent
5f5a7eb4bc
commit
5353e1ef96
@ -37,8 +37,7 @@ contents of one file to the other:
|
|||||||
dst.Close()
|
dst.Close()
|
||||||
src.Close()
|
src.Close()
|
||||||
return
|
return
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This works, but there is a bug. If the second call to os.Open fails, the
|
This works, but there is a bug. If the second call to os.Open fails, the
|
||||||
@ -64,8 +63,7 @@ files are always closed:
|
|||||||
defer dst.Close()
|
defer dst.Close()
|
||||||
|
|
||||||
return io.Copy(dst, src)
|
return io.Copy(dst, src)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Defer statements allow us to think about closing each file right after opening
|
Defer statements allow us to think about closing each file right after opening
|
||||||
@ -94,8 +92,7 @@ deferred. The deferred call will print "0" after the function returns.
|
|||||||
defer fmt.Println(i)
|
defer fmt.Println(i)
|
||||||
i++
|
i++
|
||||||
return
|
return
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
2. <i>Deferred function calls are executed in Last In First Out order
|
2. <i>Deferred function calls are executed in Last In First Out order
|
||||||
@ -111,8 +108,7 @@ This function prints "3210":
|
|||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
defer fmt.Print(i)
|
defer fmt.Print(i)
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
3. <i>Deferred functions may read and assign to the returning function's named
|
3. <i>Deferred functions may read and assign to the returning function's named
|
||||||
@ -128,8 +124,7 @@ the surrounding function returns. Thus, this function returns 2:
|
|||||||
-->func c() (i int) {
|
-->func c() (i int) {
|
||||||
defer func() { i++ }()
|
defer func() { i++ }()
|
||||||
return 1
|
return 1
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This is convenient for modifying the error return value of a function; we will
|
This is convenient for modifying the error return value of a function; we will
|
||||||
@ -188,8 +183,7 @@ func g(i int) {
|
|||||||
defer fmt.Println("Defer in g", i)
|
defer fmt.Println("Defer in g", i)
|
||||||
fmt.Println("Printing in g", i)
|
fmt.Println("Printing in g", i)
|
||||||
g(i + 1)
|
g(i + 1)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The function g takes the int i, and panics if i is greater than 3, or else it
|
The function g takes the int i, and panics if i is greater than 3, or else it
|
||||||
|
@ -12,8 +12,7 @@ returns a non-nil <code>error</code> value when it fails to open a file.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><!--{{code "progs/error.go" `/func Open/`}}
|
<pre><!--{{code "progs/error.go" `/func Open/`}}
|
||||||
-->func Open(name string) (file *File, err error)
|
-->func Open(name string) (file *File, err error)</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The following code uses <code>os.Open</code> to open a file. If an error
|
The following code uses <code>os.Open</code> to open a file. If an error
|
||||||
@ -25,8 +24,7 @@ occurs it calls <code>log.Fatal</code> to print the error message and stop.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
// do something with the open *File f
|
// do something with the open *File f</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You can get a lot done in Go knowing just this about the <code>error</code>
|
You can get a lot done in Go knowing just this about the <code>error</code>
|
||||||
@ -67,8 +65,7 @@ type errorString struct {
|
|||||||
|
|
||||||
func (e *errorString) Error() string {
|
func (e *errorString) Error() string {
|
||||||
return e.s
|
return e.s
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
You can construct one of these values with the <code>errors.New</code>
|
You can construct one of these values with the <code>errors.New</code>
|
||||||
@ -80,8 +77,7 @@ and returns as an <code>error</code> value.
|
|||||||
-->// New returns an error that formats as the given text.
|
-->// New returns an error that formats as the given text.
|
||||||
func New(text string) error {
|
func New(text string) error {
|
||||||
return &errorString{text}
|
return &errorString{text}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Here's how you might use <code>errors.New</code>:
|
Here's how you might use <code>errors.New</code>:
|
||||||
@ -93,8 +89,7 @@ Here's how you might use <code>errors.New</code>:
|
|||||||
return 0, errors.New("math: square root of negative number")
|
return 0, errors.New("math: square root of negative number")
|
||||||
}
|
}
|
||||||
// implementation
|
// implementation
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A caller passing a negative argument to <code>Sqrt</code> receives a non-nil
|
A caller passing a negative argument to <code>Sqrt</code> receives a non-nil
|
||||||
@ -108,8 +103,7 @@ A caller passing a negative argument to <code>Sqrt</code> receives a non-nil
|
|||||||
-->f, err := Sqrt(-1)
|
-->f, err := Sqrt(-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The <a href="/pkg/fmt/">fmt</a> package formats an <code>error</code> value
|
The <a href="/pkg/fmt/">fmt</a> package formats an <code>error</code> value
|
||||||
@ -133,8 +127,7 @@ rules and returns it as an <code>error</code> created by
|
|||||||
<pre><!--{{code "progs/error.go" `/fmtError/` `/STOP/`}}
|
<pre><!--{{code "progs/error.go" `/fmtError/` `/STOP/`}}
|
||||||
-->if f < 0 {
|
-->if f < 0 {
|
||||||
return 0, fmt.Errorf("math: square root of negative number %g", f)
|
return 0, fmt.Errorf("math: square root of negative number %g", f)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
In many cases <code>fmt.Errorf</code> is good enough, but since
|
In many cases <code>fmt.Errorf</code> is good enough, but since
|
||||||
@ -153,8 +146,7 @@ error implementation instead of using <code>errors.errorString</code>:
|
|||||||
|
|
||||||
func (f NegativeSqrtError) Error() string {
|
func (f NegativeSqrtError) Error() string {
|
||||||
return fmt.Sprintf("math: square root of negative number %g", float64(f))
|
return fmt.Sprintf("math: square root of negative number %g", float64(f))
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A sophisticated caller can then use a
|
A sophisticated caller can then use a
|
||||||
@ -176,8 +168,7 @@ returns when it encounters a syntax error parsing a JSON blob.
|
|||||||
Offset int64 // error occurred after reading Offset bytes
|
Offset int64 // error occurred after reading Offset bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *SyntaxError) Error() string { return e.msg }
|
func (e *SyntaxError) Error() string { return e.msg }</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The <code>Offset</code> field isn't even shown in the default formatting of the
|
The <code>Offset</code> field isn't even shown in the default formatting of the
|
||||||
@ -192,8 +183,7 @@ messages:
|
|||||||
return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
|
return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
(This is a slightly simplified version of some
|
(This is a slightly simplified version of some
|
||||||
@ -232,8 +222,7 @@ up otherwise.
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<b>Simplifying repetitive error handling</b>
|
<b>Simplifying repetitive error handling</b>
|
||||||
@ -269,8 +258,7 @@ func viewRecord(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err := viewTemplate.Execute(w, record); err != nil {
|
if err := viewTemplate.Execute(w, record); err != nil {
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This function handles errors returned by the <code>datastore.Get</code>
|
This function handles errors returned by the <code>datastore.Get</code>
|
||||||
@ -287,8 +275,7 @@ type that includes an <code>error</code> return value:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><!--{{code "progs/error3.go" `/type appHandler/`}}
|
<pre><!--{{code "progs/error3.go" `/type appHandler/`}}
|
||||||
-->type appHandler func(http.ResponseWriter, *http.Request) error
|
-->type appHandler func(http.ResponseWriter, *http.Request) error</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Then we can change our <code>viewRecord</code> function to return errors:
|
Then we can change our <code>viewRecord</code> function to return errors:
|
||||||
@ -303,8 +290,7 @@ Then we can change our <code>viewRecord</code> function to return errors:
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return viewTemplate.Execute(w, record)
|
return viewTemplate.Execute(w, record)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This is simpler than the original version, but the <a
|
This is simpler than the original version, but the <a
|
||||||
@ -319,8 +305,7 @@ To fix this we can implement the <code>http.Handler</code> interface's
|
|||||||
if err := fn(w, r); err != nil {
|
if err := fn(w, r); err != nil {
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The <code>ServeHTTP</code> method calls the <code>appHandler</code> function
|
The <code>ServeHTTP</code> method calls the <code>appHandler</code> function
|
||||||
@ -339,8 +324,7 @@ Now when registering <code>viewRecord</code> with the http package we use the
|
|||||||
<pre><!--{{code "progs/error3.go" `/func init/` `/STOP/`}}
|
<pre><!--{{code "progs/error3.go" `/func init/` `/STOP/`}}
|
||||||
-->func init() {
|
-->func init() {
|
||||||
http.Handle("/view", appHandler(viewRecord))
|
http.Handle("/view", appHandler(viewRecord))
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
With this basic error handling infrastructure in place, we can make it more
|
With this basic error handling infrastructure in place, we can make it more
|
||||||
@ -360,16 +344,14 @@ To do this we create an <code>appError</code> struct containing an
|
|||||||
Error error
|
Error error
|
||||||
Message string
|
Message string
|
||||||
Code int
|
Code int
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Next we modify the appHandler type to return <code>*appError</code> values:
|
Next we modify the appHandler type to return <code>*appError</code> values:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><!--{{code "progs/error4.go" `/type appHandler/`}}
|
<pre><!--{{code "progs/error4.go" `/type appHandler/`}}
|
||||||
-->type appHandler func(http.ResponseWriter, *http.Request) *appError
|
-->type appHandler func(http.ResponseWriter, *http.Request) *appError</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
(It's usually a mistake to pass back the concrete type of an error rather than
|
(It's usually a mistake to pass back the concrete type of an error rather than
|
||||||
@ -392,8 +374,7 @@ console:
|
|||||||
c.Errorf("%v", e.Error)
|
c.Errorf("%v", e.Error)
|
||||||
http.Error(w, e.Message, e.Code)
|
http.Error(w, e.Message, e.Code)
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Finally, we update <code>viewRecord</code> to the new function signature and
|
Finally, we update <code>viewRecord</code> to the new function signature and
|
||||||
@ -412,8 +393,7 @@ have it return more context when it encounters an error:
|
|||||||
return &appError{err, "Can't display record", 500}
|
return &appError{err, "Can't display record", 500}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This version of <code>viewRecord</code> is the same length as the original, but
|
This version of <code>viewRecord</code> is the same length as the original, but
|
||||||
|
@ -1690,8 +1690,7 @@ const (
|
|||||||
EB
|
EB
|
||||||
ZB
|
ZB
|
||||||
YB
|
YB
|
||||||
)
|
)</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The ability to attach a method such as <code>String</code> to a
|
The ability to attach a method such as <code>String</code> to a
|
||||||
type makes it possible for such values to format themselves
|
type makes it possible for such values to format themselves
|
||||||
@ -1718,8 +1717,7 @@ automatically for printing, even as part of a general type.
|
|||||||
return fmt.Sprintf("%.2fKB", float64(b/KB))
|
return fmt.Sprintf("%.2fKB", float64(b/KB))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%.2fB", float64(b))
|
return fmt.Sprintf("%.2fB", float64(b))
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
(The <code>float64</code> conversions prevent <code>Sprintf</code>
|
(The <code>float64</code> conversions prevent <code>Sprintf</code>
|
||||||
from recurring back through the <code>String</code> method for
|
from recurring back through the <code>String</code> method for
|
||||||
@ -1893,8 +1891,7 @@ func (s Sequence) String() string {
|
|||||||
str += fmt.Sprint(elem)
|
str += fmt.Sprint(elem)
|
||||||
}
|
}
|
||||||
return str + "]"
|
return str + "]"
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<h3 id="conversions">Conversions</h3>
|
<h3 id="conversions">Conversions</h3>
|
||||||
|
|
||||||
@ -3044,8 +3041,7 @@ value="Show QR" name=qr>
|
|||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The pieces up to <code>main</code> should be easy to follow.
|
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
|
The one flag sets a default HTTP port for our server. The template
|
||||||
|
36
doc/go1.html
36
doc/go1.html
@ -45,8 +45,7 @@ call.
|
|||||||
|
|
||||||
<pre><!--{{code "progs/go1.go" `/greeting := ..byte/` `/append.*hello/`}}
|
<pre><!--{{code "progs/go1.go" `/greeting := ..byte/` `/append.*hello/`}}
|
||||||
-->greeting := []byte{}
|
-->greeting := []byte{}
|
||||||
greeting = append(greeting, []byte("hello ")...)
|
greeting = append(greeting, []byte("hello ")...)</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
By analogy with the similar property of <code>copy</code>, Go 1
|
By analogy with the similar property of <code>copy</code>, Go 1
|
||||||
@ -55,8 +54,7 @@ slice; the conversion is no longer necessary:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><!--{{code "progs/go1.go" `/append.*world/`}}
|
<pre><!--{{code "progs/go1.go" `/append.*world/`}}
|
||||||
--> greeting = append(greeting, "world"...)
|
-->greeting = append(greeting, "world"...)</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Updating</em>:
|
<em>Updating</em>:
|
||||||
@ -124,8 +122,7 @@ All four of the initializations in this example are legal; the last one was ille
|
|||||||
{"Feb", 14},
|
{"Feb", 14},
|
||||||
{"Nov", 11},
|
{"Nov", 11},
|
||||||
{"Dec", 25},
|
{"Dec", 25},
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Updating</em>:
|
<em>Updating</em>:
|
||||||
@ -152,8 +149,7 @@ func init() {
|
|||||||
c := make(chan int)
|
c := make(chan int)
|
||||||
go initializationFunction(c)
|
go initializationFunction(c)
|
||||||
PackageGlobal = <-c
|
PackageGlobal = <-c
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Updating</em>:
|
<em>Updating</em>:
|
||||||
@ -192,8 +188,7 @@ relatives now take and return a <code>rune</code>.
|
|||||||
epsilon := unicode.ToLower(DELTA + 1)
|
epsilon := unicode.ToLower(DELTA + 1)
|
||||||
if epsilon != 'δ'+1 {
|
if epsilon != 'δ'+1 {
|
||||||
log.Fatal("inconsistent casing for Greek")
|
log.Fatal("inconsistent casing for Greek")
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Updating</em>:
|
<em>Updating</em>:
|
||||||
@ -236,8 +231,7 @@ function, <code>delete</code>. The call
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><!--{{code "progs/go1.go" `/delete\(m, k\)/`}}
|
<pre><!--{{code "progs/go1.go" `/delete\(m, k\)/`}}
|
||||||
--> delete(m, k)
|
-->delete(m, k)</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
will delete the map entry retrieved by the expression <code>m[k]</code>.
|
will delete the map entry retrieved by the expression <code>m[k]</code>.
|
||||||
@ -268,8 +262,7 @@ Code should not assume that the elements are visited in any particular order.
|
|||||||
for name, value := range m {
|
for name, value := range m {
|
||||||
// This loop should not assume Sunday will be visited first.
|
// This loop should not assume Sunday will be visited first.
|
||||||
f(name, value)
|
f(name, value)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Updating</em>:
|
<em>Updating</em>:
|
||||||
@ -308,8 +301,7 @@ These examples illustrate the behavior.
|
|||||||
sb[j], j = 2, 1 // sets sb[0] = 2, j = 1
|
sb[j], j = 2, 1 // sets sb[0] = 2, j = 1
|
||||||
|
|
||||||
sc := []int{1, 2, 3}
|
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)
|
sc[0], sc[0] = 1, 2 // sets sc[0] = 1, then sc[0] = 2 (so sc[0] = 2 at end)</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Updating</em>:
|
<em>Updating</em>:
|
||||||
@ -427,8 +419,7 @@ As a result, structs and arrays can now be used as map keys:
|
|||||||
Christmas: true,
|
Christmas: true,
|
||||||
Thanksgiving: true,
|
Thanksgiving: true,
|
||||||
}
|
}
|
||||||
fmt.Printf("Christmas is a holiday: %t\n", holiday[Christmas])
|
fmt.Printf("Christmas is a holiday: %t\n", holiday[Christmas])</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Note that equality is still undefined for slices, for which the
|
Note that equality is still undefined for slices, for which the
|
||||||
@ -575,8 +566,7 @@ does for <code>String</code>, for easy printing of error values.
|
|||||||
|
|
||||||
func (se *SyntaxError) Error() string {
|
func (se *SyntaxError) Error() string {
|
||||||
return fmt.Sprintf("%s:%d: %s", se.File, se.Line, se.Message)
|
return fmt.Sprintf("%s:%d: %s", se.File, se.Line, se.Message)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
All standard packages have been updated to use the new interface; the old <code>os.Error</code> is gone.
|
All standard packages have been updated to use the new interface; the old <code>os.Error</code> is gone.
|
||||||
@ -595,8 +585,7 @@ to turn a string into an error. It replaces the old <code>os.NewError</code>.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><!--{{code "progs/go1.go" `/ErrSyntax/`}}
|
<pre><!--{{code "progs/go1.go" `/ErrSyntax/`}}
|
||||||
--> var ErrSyntax = errors.New("syntax error")
|
-->var ErrSyntax = errors.New("syntax error")</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<em>Updating</em>:
|
<em>Updating</em>:
|
||||||
@ -677,8 +666,7 @@ func sleepUntil(wakeup time.Time) {
|
|||||||
delta := wakeup.Sub(now) // A Duration.
|
delta := wakeup.Sub(now) // A Duration.
|
||||||
log.Printf("Sleeping for %.3fs", delta.Seconds())
|
log.Printf("Sleeping for %.3fs", delta.Seconds())
|
||||||
time.Sleep(delta)
|
time.Sleep(delta)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The new types, methods, and constants have been propagated through
|
The new types, methods, and constants have been propagated through
|
||||||
|
@ -33,8 +33,7 @@ import fmt "fmt" // Package implementing formatted I/O.
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
|
fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Every Go source file declares, using a <code>package</code> statement, which package it's part of.
|
Every Go source file declares, using a <code>package</code> statement, which package it's part of.
|
||||||
It may also import other packages to use their facilities.
|
It may also import other packages to use their facilities.
|
||||||
@ -144,8 +143,7 @@ func main() {
|
|||||||
s += Newline
|
s += Newline
|
||||||
}
|
}
|
||||||
os.Stdout.WriteString(s)
|
os.Stdout.WriteString(s)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
This program is small but it's doing a number of new things. In the last example,
|
This program is small but it's doing a number of new things. In the last example,
|
||||||
we saw <code>func</code> introduce a function. The keywords <code>var</code>, <code>const</code>, and <code>type</code>
|
we saw <code>func</code> introduce a function. The keywords <code>var</code>, <code>const</code>, and <code>type</code>
|
||||||
@ -211,8 +209,7 @@ The <code>:=</code> operator is used a lot in Go to represent an initializing de
|
|||||||
There's one in the <code>for</code> clause on the next line:
|
There's one in the <code>for</code> clause on the next line:
|
||||||
<p>
|
<p>
|
||||||
<pre><!--{{code "progs/echo.go" `/for/`}}
|
<pre><!--{{code "progs/echo.go" `/for/`}}
|
||||||
--> for i := 0; i < flag.NArg(); i++ {
|
-->for i := 0; i < flag.NArg(); i++ {</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The <code>flag</code> package has parsed the arguments and left the non-flag arguments
|
The <code>flag</code> package has parsed the arguments and left the non-flag arguments
|
||||||
in a list that can be iterated over in the obvious way.
|
in a list that can be iterated over in the obvious way.
|
||||||
@ -267,8 +264,7 @@ reassigning it. This snippet from <code>strings.go</code> is legal code:
|
|||||||
}
|
}
|
||||||
s = "good bye"
|
s = "good bye"
|
||||||
var p *string = &s
|
var p *string = &s
|
||||||
*p = "ciao"
|
*p = "ciao"</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
However the following statements are illegal because they would modify
|
However the following statements are illegal because they would modify
|
||||||
a <code>string</code> value:
|
a <code>string</code> value:
|
||||||
@ -340,8 +336,7 @@ Using slices one can write this function (from <code>sum.go</code>):
|
|||||||
s += a[i]
|
s += a[i]
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it
|
Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it
|
||||||
after the parameter list.
|
after the parameter list.
|
||||||
@ -493,8 +488,7 @@ import (
|
|||||||
type File struct {
|
type File struct {
|
||||||
fd int // file descriptor number
|
fd int // file descriptor number
|
||||||
name string // file name at Open time
|
name string // file name at Open time
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The first few lines declare the name of the
|
The first few lines declare the name of the
|
||||||
package—<code>file</code>—and then import two packages. The <code>os</code>
|
package—<code>file</code>—and then import two packages. The <code>os</code>
|
||||||
@ -535,8 +529,7 @@ First, though, here is a factory to create a <code>File</code>:
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &File{fd, name}
|
return &File{fd, name}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
This returns a pointer to a new <code>File</code> structure with the file descriptor and name
|
This returns a pointer to a new <code>File</code> structure with the file descriptor and name
|
||||||
filled in. This code uses Go's notion of a ''composite literal'', analogous to
|
filled in. This code uses Go's notion of a ''composite literal'', analogous to
|
||||||
@ -560,8 +553,7 @@ We can use the factory to construct some familiar, exported variables of type <c
|
|||||||
Stdin = newFile(syscall.Stdin, "/dev/stdin")
|
Stdin = newFile(syscall.Stdin, "/dev/stdin")
|
||||||
Stdout = newFile(syscall.Stdout, "/dev/stdout")
|
Stdout = newFile(syscall.Stdout, "/dev/stdout")
|
||||||
Stderr = newFile(syscall.Stderr, "/dev/stderr")
|
Stderr = newFile(syscall.Stderr, "/dev/stderr")
|
||||||
)
|
)</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The <code>newFile</code> function was not exported because it's internal. The proper,
|
The <code>newFile</code> function was not exported because it's internal. The proper,
|
||||||
exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
|
exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
|
||||||
@ -570,8 +562,7 @@ exported factory to use is <code>OpenFile</code> (we'll explain that name in a m
|
|||||||
-->func OpenFile(name string, mode int, perm uint32) (file *File, err error) {
|
-->func OpenFile(name string, mode int, perm uint32) (file *File, err error) {
|
||||||
r, err := syscall.Open(name, mode, perm)
|
r, err := syscall.Open(name, mode, perm)
|
||||||
return newFile(r, name), err
|
return newFile(r, name), err
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
There are a number of new things in these few lines. First, <code>OpenFile</code> returns
|
There are a number of new things in these few lines. First, <code>OpenFile</code> returns
|
||||||
multiple values, a <code>File</code> and an error (more about errors in a moment).
|
multiple values, a <code>File</code> and an error (more about errors in a moment).
|
||||||
@ -613,14 +604,12 @@ the tricky standard arguments to open and, especially, to create a file:
|
|||||||
|
|
||||||
func Open(name string) (file *File, err error) {
|
func Open(name string) (file *File, err error) {
|
||||||
return OpenFile(name, O_RDONLY, 0)
|
return OpenFile(name, O_RDONLY, 0)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
<pre><!--{{code "progs/file.go" `/func.Create/` `/^}/`}}
|
<pre><!--{{code "progs/file.go" `/func.Create/` `/^}/`}}
|
||||||
-->func Create(name string) (file *File, err error) {
|
-->func Create(name string) (file *File, err error) {
|
||||||
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
|
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Back to our main story.
|
Back to our main story.
|
||||||
Now that we can build <code>Files</code>, we can write methods for them. To declare
|
Now that we can build <code>Files</code>, we can write methods for them. To declare
|
||||||
@ -657,8 +646,7 @@ func (file *File) Write(b []byte) (ret int, err error) {
|
|||||||
|
|
||||||
func (file *File) String() string {
|
func (file *File) String() string {
|
||||||
return file.name
|
return file.name
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
There is no implicit <code>this</code> and the receiver variable must be used to access
|
There is no implicit <code>this</code> and the receiver variable must be used to access
|
||||||
members of the structure. Methods are not declared within
|
members of the structure. Methods are not declared within
|
||||||
@ -692,8 +680,7 @@ func main() {
|
|||||||
fmt.Printf("can't open file; err=%s\n", err.Error())
|
fmt.Printf("can't open file; err=%s\n", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The ''<code>./</code>'' in the import of ''<code>./file</code>'' tells the compiler
|
The ''<code>./</code>'' in the import of ''<code>./file</code>'' tells the compiler
|
||||||
to use our own package rather than
|
to use our own package rather than
|
||||||
@ -761,8 +748,7 @@ func main() {
|
|||||||
cat(f)
|
cat(f)
|
||||||
f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
By now this should be easy to follow, but the <code>switch</code> statement introduces some
|
By now this should be easy to follow, but the <code>switch</code> statement introduces some
|
||||||
new features. Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an
|
new features. Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an
|
||||||
@ -794,8 +780,7 @@ Here is code from <code>progs/cat_rot13.go</code>:
|
|||||||
-->type reader interface {
|
-->type reader interface {
|
||||||
Read(b []byte) (ret int, err error)
|
Read(b []byte) (ret int, err error)
|
||||||
String() string
|
String() string
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Any type that has the two methods of <code>reader</code>—regardless of whatever
|
Any type that has the two methods of <code>reader</code>—regardless of whatever
|
||||||
other methods the type may also have—is said to <i>implement</i> the
|
other methods the type may also have—is said to <i>implement</i> the
|
||||||
@ -827,16 +812,14 @@ func (r13 *rotate13) Read(b []byte) (ret int, err error) {
|
|||||||
func (r13 *rotate13) String() string {
|
func (r13 *rotate13) String() string {
|
||||||
return r13.source.String()
|
return r13.source.String()
|
||||||
}
|
}
|
||||||
// end of rotate13 implementation
|
// end of rotate13 implementation</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
(The <code>rot13</code> function called in <code>Read</code> is trivial and not worth reproducing here.)
|
(The <code>rot13</code> function called in <code>Read</code> is trivial and not worth reproducing here.)
|
||||||
<p>
|
<p>
|
||||||
To use the new feature, we define a flag:
|
To use the new feature, we define a flag:
|
||||||
<p>
|
<p>
|
||||||
<pre><!--{{code "progs/cat_rot13.go" `/rot13Flag/`}}
|
<pre><!--{{code "progs/cat_rot13.go" `/rot13Flag/`}}
|
||||||
-->var rot13Flag = flag.Bool("rot13", false, "rot13 the input")
|
-->var rot13Flag = flag.Bool("rot13", false, "rot13 the input")</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
and use it from within a mostly unchanged <code>cat</code> function:
|
and use it from within a mostly unchanged <code>cat</code> function:
|
||||||
<p>
|
<p>
|
||||||
@ -863,8 +846,7 @@ and use it from within a mostly unchanged <code>cat</code> function:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
(We could also do the wrapping in <code>main</code> and leave <code>cat</code> mostly alone, except
|
(We could also do the wrapping in <code>main</code> and leave <code>cat</code> mostly alone, except
|
||||||
for changing the type of the argument; consider that an exercise.)
|
for changing the type of the argument; consider that an exercise.)
|
||||||
@ -918,8 +900,7 @@ As an example, consider this simple sort algorithm taken from <code>progs/sort.g
|
|||||||
data.Swap(j, j-1)
|
data.Swap(j, j-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The code needs only three methods, which we wrap into sort's <code>Interface</code>:
|
The code needs only three methods, which we wrap into sort's <code>Interface</code>:
|
||||||
<p>
|
<p>
|
||||||
@ -928,8 +909,7 @@ The code needs only three methods, which we wrap into sort's <code>Interface</co
|
|||||||
Len() int
|
Len() int
|
||||||
Less(i, j int) bool
|
Less(i, j int) bool
|
||||||
Swap(i, j int)
|
Swap(i, j int)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
We can apply <code>Sort</code> to any type that implements <code>Len</code>, <code>Less</code>, and <code>Swap</code>.
|
We can apply <code>Sort</code> to any type that implements <code>Len</code>, <code>Less</code>, and <code>Swap</code>.
|
||||||
The <code>sort</code> package includes the necessary methods to allow sorting of
|
The <code>sort</code> package includes the necessary methods to allow sorting of
|
||||||
@ -940,8 +920,7 @@ arrays of integers, strings, etc.; here's the code for arrays of <code>int</code
|
|||||||
|
|
||||||
func (p IntSlice) Len() int { return len(p) }
|
func (p IntSlice) Len() int { return len(p) }
|
||||||
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
|
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
|
||||||
func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Here we see methods defined for non-<code>struct</code> types. You can define methods
|
Here we see methods defined for non-<code>struct</code> types. You can define methods
|
||||||
for any type you define and name in your package.
|
for any type you define and name in your package.
|
||||||
@ -958,8 +937,7 @@ to test that the result is sorted.
|
|||||||
if !sort.IsSorted(a) {
|
if !sort.IsSorted(a) {
|
||||||
panic("fail")
|
panic("fail")
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
If we have a new type we want to be able to sort, all we need to do is
|
If we have a new type we want to be able to sort, all we need to do is
|
||||||
to implement the three methods for that type, like this:
|
to implement the three methods for that type, like this:
|
||||||
@ -977,8 +955,7 @@ type dayArray struct {
|
|||||||
|
|
||||||
func (p *dayArray) Len() int { return len(p.data) }
|
func (p *dayArray) Len() int { return len(p.data) }
|
||||||
func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num }
|
func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num }
|
||||||
func (p *dayArray) Swap(i, j int) { p.data[i], p.data[j] = p.data[j], p.data[i] }
|
func (p *dayArray) Swap(i, j int) { p.data[i], p.data[j] = p.data[j], p.data[i] }</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
<p>
|
<p>
|
||||||
<h2>Printing</h2>
|
<h2>Printing</h2>
|
||||||
@ -1014,8 +991,7 @@ integer and can do the right thing for you. The snippet
|
|||||||
<p>
|
<p>
|
||||||
<pre><!--{{code "progs/print.go" 10 11}}
|
<pre><!--{{code "progs/print.go" 10 11}}
|
||||||
-->var u64 uint64 = 1<<64 - 1
|
-->var u64 uint64 = 1<<64 - 1
|
||||||
fmt.Printf("%d %d\n", u64, int64(u64))
|
fmt.Printf("%d %d\n", u64, int64(u64))</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
prints
|
prints
|
||||||
<p>
|
<p>
|
||||||
@ -1033,8 +1009,7 @@ appropriate style, any value, even an array or structure. The output of
|
|||||||
}
|
}
|
||||||
t := T{77, "Sunset Strip"}
|
t := T{77, "Sunset Strip"}
|
||||||
a := []int{1, 2, 3, 4}
|
a := []int{1, 2, 3, 4}
|
||||||
fmt.Printf("%v %v %v\n", u64, t, a)
|
fmt.Printf("%v %v %v\n", u64, t, a)</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
is
|
is
|
||||||
<p>
|
<p>
|
||||||
@ -1051,8 +1026,7 @@ to that of the <code>Printf</code> call above.
|
|||||||
<p>
|
<p>
|
||||||
<pre><!--{{code "progs/print.go" 21 22}}
|
<pre><!--{{code "progs/print.go" 21 22}}
|
||||||
-->fmt.Print(u64, " ", t, " ", a, "\n")
|
-->fmt.Print(u64, " ", t, " ", a, "\n")
|
||||||
fmt.Println(u64, t, a)
|
fmt.Println(u64, t, a)</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format,
|
If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format,
|
||||||
just give it a <code>String</code> method that returns a string. The print
|
just give it a <code>String</code> method that returns a string. The print
|
||||||
@ -1073,8 +1047,7 @@ func (t *testType) String() string {
|
|||||||
func main() {
|
func main() {
|
||||||
t := &testType{77, "Sunset Strip"}
|
t := &testType{77, "Sunset Strip"}
|
||||||
fmt.Println(t)
|
fmt.Println(t)
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Since <code>*testType</code> has a <code>String</code> method, the
|
Since <code>*testType</code> has a <code>String</code> method, the
|
||||||
default formatter for that type will use it and produce the output
|
default formatter for that type will use it and produce the output
|
||||||
@ -1200,8 +1173,7 @@ func generate(ch chan int) {
|
|||||||
for i := 2; ; i++ {
|
for i := 2; ; i++ {
|
||||||
ch <- i // Send 'i' to channel 'ch'.
|
ch <- i // Send 'i' to channel 'ch'.
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The <code>generate</code> function sends the sequence 2, 3, 4, 5, ... to its
|
The <code>generate</code> function sends the sequence 2, 3, 4, 5, ... to its
|
||||||
argument channel, <code>ch</code>, using the binary communications operator <code><-</code>.
|
argument channel, <code>ch</code>, using the binary communications operator <code><-</code>.
|
||||||
@ -1223,8 +1195,7 @@ func filter(in, out chan int, prime int) {
|
|||||||
out <- i // Send 'i' to channel 'out'.
|
out <- i // Send 'i' to channel 'out'.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The generator and filters execute concurrently. Go has
|
The generator and filters execute concurrently. Go has
|
||||||
its own model of process/threads/light-weight processes/coroutines,
|
its own model of process/threads/light-weight processes/coroutines,
|
||||||
@ -1262,8 +1233,7 @@ together:
|
|||||||
go filter(ch, ch1, prime)
|
go filter(ch, ch1, prime)
|
||||||
ch = ch1
|
ch = ch1
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The first line of <code>main</code> creates the initial channel to pass to <code>generate</code>, which it
|
The first line of <code>main</code> creates the initial channel to pass to <code>generate</code>, which it
|
||||||
then starts up. As each prime pops out of the channel, a new <code>filter</code>
|
then starts up. As each prime pops out of the channel, a new <code>filter</code>
|
||||||
@ -1283,8 +1253,7 @@ of <code>generate</code>, from <code>progs/sieve1.go</code>:
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return ch
|
return ch
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
This version does all the setup internally. It creates the output
|
This version does all the setup internally. It creates the output
|
||||||
channel, launches a goroutine running a function literal, and
|
channel, launches a goroutine running a function literal, and
|
||||||
@ -1309,8 +1278,7 @@ The same change can be made to <code>filter</code>:
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return out
|
return out
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The <code>sieve</code> function's main loop becomes simpler and clearer as a
|
The <code>sieve</code> function's main loop becomes simpler and clearer as a
|
||||||
result, and while we're at it let's turn it into a factory too:
|
result, and while we're at it let's turn it into a factory too:
|
||||||
@ -1327,8 +1295,7 @@ result, and while we're at it let's turn it into a factory too:
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return out
|
return out
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Now <code>main</code>'s interface to the prime sieve is a channel of primes:
|
Now <code>main</code>'s interface to the prime sieve is a channel of primes:
|
||||||
<p>
|
<p>
|
||||||
@ -1338,8 +1305,7 @@ Now <code>main</code>'s interface to the prime sieve is a channel of primes:
|
|||||||
for i := 0; i < 100; i++ { // Print the first hundred primes.
|
for i := 0; i < 100; i++ { // Print the first hundred primes.
|
||||||
fmt.Println(<-primes)
|
fmt.Println(<-primes)
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
<h2>Multiplexing</h2>
|
<h2>Multiplexing</h2>
|
||||||
<p>
|
<p>
|
||||||
@ -1354,8 +1320,7 @@ that will be used for the reply.
|
|||||||
-->type request struct {
|
-->type request struct {
|
||||||
a, b int
|
a, b int
|
||||||
replyc chan int
|
replyc chan int
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The server will be trivial: it will do simple binary operations on integers. Here's the
|
The server will be trivial: it will do simple binary operations on integers. Here's the
|
||||||
code that invokes the operation and responds to the request:
|
code that invokes the operation and responds to the request:
|
||||||
@ -1366,8 +1331,7 @@ code that invokes the operation and responds to the request:
|
|||||||
func run(op binOp, req *request) {
|
func run(op binOp, req *request) {
|
||||||
reply := op(req.a, req.b)
|
reply := op(req.a, req.b)
|
||||||
req.replyc <- reply
|
req.replyc <- reply
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The type declaration makes <code>binOp</code> represent a function taking two integers and
|
The type declaration makes <code>binOp</code> represent a function taking two integers and
|
||||||
returning a third.
|
returning a third.
|
||||||
@ -1381,8 +1345,7 @@ a long-running operation, starting a goroutine to do the actual work.
|
|||||||
req := <-service
|
req := <-service
|
||||||
go run(op, req) // don't wait for it
|
go run(op, req) // don't wait for it
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
There's a new feature in the signature of <code>server</code>: the type of the
|
There's a new feature in the signature of <code>server</code>: the type of the
|
||||||
<code>service</code> channel specifies the direction of communication.
|
<code>service</code> channel specifies the direction of communication.
|
||||||
@ -1403,8 +1366,7 @@ connected to it:
|
|||||||
req := make(chan *request)
|
req := make(chan *request)
|
||||||
go server(op, req)
|
go server(op, req)
|
||||||
return req
|
return req
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
The returned channel is send only, even though the channel was created bidirectionally.
|
The returned channel is send only, even though the channel was created bidirectionally.
|
||||||
The read end is passed to <code>server</code>, while the send end is returned
|
The read end is passed to <code>server</code>, while the send end is returned
|
||||||
@ -1441,8 +1403,7 @@ does it check the results.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println("done")
|
fmt.Println("done")
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
One annoyance with this program is that it doesn't shut down the server cleanly; when <code>main</code> returns
|
One annoyance with this program is that it doesn't shut down the server cleanly; when <code>main</code> returns
|
||||||
there are a number of lingering goroutines blocked on communication. To solve this,
|
there are a number of lingering goroutines blocked on communication. To solve this,
|
||||||
@ -1454,8 +1415,7 @@ we can provide a second, <code>quit</code> channel to the server:
|
|||||||
quit = make(chan bool)
|
quit = make(chan bool)
|
||||||
go server(op, service, quit)
|
go server(op, service, quit)
|
||||||
return service, quit
|
return service, quit
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
It passes the quit channel to the <code>server</code> function, which uses it like this:
|
It passes the quit channel to the <code>server</code> function, which uses it like this:
|
||||||
<p>
|
<p>
|
||||||
@ -1469,8 +1429,7 @@ It passes the quit channel to the <code>server</code> function, which uses it li
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
Inside <code>server</code>, the <code>select</code> statement chooses which of the multiple communications
|
Inside <code>server</code>, the <code>select</code> statement chooses which of the multiple communications
|
||||||
listed by its cases can proceed. If all are blocked, it waits until one can proceed; if
|
listed by its cases can proceed. If all are blocked, it waits until one can proceed; if
|
||||||
@ -1483,12 +1442,10 @@ All that's left is to strobe the <code>quit</code> channel
|
|||||||
at the end of main:
|
at the end of main:
|
||||||
<p>
|
<p>
|
||||||
<pre><!--{{code "progs/server1.go" `/adder,.quit/`}}
|
<pre><!--{{code "progs/server1.go" `/adder,.quit/`}}
|
||||||
--> adder, quit := startServer(func(a, b int) int { return a + b })
|
-->adder, quit := startServer(func(a, b int) int { return a + b })</pre>
|
||||||
</pre>
|
|
||||||
...
|
...
|
||||||
<pre><!--{{code "progs/server1.go" `/quit....true/`}}
|
<pre><!--{{code "progs/server1.go" `/quit....true/`}}
|
||||||
--> quit <- true
|
-->quit <- true</pre>
|
||||||
</pre>
|
|
||||||
<p>
|
<p>
|
||||||
There's a lot more to Go programming and concurrent programming in general but this
|
There's a lot more to Go programming and concurrent programming in general but this
|
||||||
quick tour should give you some of the basics.
|
quick tour should give you some of the basics.
|
||||||
|
@ -113,6 +113,8 @@ func code(file string, arg ...interface{}) (string, error) {
|
|||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("incorrect code invocation: code %q %q", file, arg)
|
return "", fmt.Errorf("incorrect code invocation: code %q %q", file, arg)
|
||||||
}
|
}
|
||||||
|
// Trim spaces from output.
|
||||||
|
text = strings.TrimSpace(text)
|
||||||
// Replace tabs by spaces, which work better in HTML.
|
// Replace tabs by spaces, which work better in HTML.
|
||||||
text = strings.Replace(text, "\t", " ", -1)
|
text = strings.Replace(text, "\t", " ", -1)
|
||||||
// Escape the program text for HTML.
|
// Escape the program text for HTML.
|
||||||
|
Loading…
Reference in New Issue
Block a user