diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-08-03 16:54:30 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-08-03 16:54:30 +0200 |
commit | 28592ee1ea1f5cdffcf85472f9de0285d928cf12 (patch) | |
tree | 32944e18b23f7fe4a0818a694aa2a6dfb1835463 /doc/go_tutorial.html | |
parent | e836bee4716dc0d4d913537ad3ad1925a7ac32d0 (diff) | |
download | golang-upstream/59.tar.gz |
Imported Upstream version 59upstream/59
Diffstat (limited to 'doc/go_tutorial.html')
-rw-r--r-- | doc/go_tutorial.html | 1049 |
1 files changed, 525 insertions, 524 deletions
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html index aa85134b3..822f9626e 100644 --- a/doc/go_tutorial.html +++ b/doc/go_tutorial.html @@ -26,14 +26,14 @@ cleanliness, blank lines remain blank. <p> Let's start in the usual way: <p> -<pre> <!-- progs/helloworld.go /package/ END --> -05 package main +<pre><!-- progs/helloworld.go /package/ $ +-->package main -07 import fmt "fmt" // Package implementing formatted I/O. +import fmt "fmt" // Package implementing formatted I/O. -09 func main() { -10 fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n") -11 } +func main() { + fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n") +} </pre> <p> Every Go source file declares, using a <code>package</code> statement, which package it's part of. @@ -51,8 +51,8 @@ String constants can contain Unicode characters, encoded in UTF-8. The comment convention is the same as in C++: <p> <pre> - /* ... */ - // ... +/* ... */ +// ... </pre> <p> Later we'll have much more to say about printing. @@ -96,67 +96,67 @@ a more robust run-time system although <code>gccgo</code> is catching up. Here's how to compile and run our program. With <code>6g</code>, say, <p> <pre> - $ 6g helloworld.go # compile; object goes into helloworld.6 - $ 6l helloworld.6 # link; output goes into 6.out - $ 6.out - Hello, world; or Καλημέρα κόσμε; or こんにちは 世界 - $ +$ 6g helloworld.go # compile; object goes into helloworld.6 +$ 6l helloworld.6 # link; output goes into 6.out +$ 6.out +Hello, world; or Καλημέρα κόσμε; or こんにちは 世界 +$ </pre> <p> With <code>gccgo</code> it looks a little more traditional. <p> <pre> - $ gccgo helloworld.go - $ a.out - Hello, world; or Καλημέρα κόσμε; or こんにちは 世界 - $ +$ gccgo helloworld.go +$ a.out +Hello, world; or Καλημέρα κόσμε; or こんにちは 世界 +$ </pre> <p> <h2>Echo</h2> <p> Next up, here's a version of the Unix utility <code>echo(1)</code>: <p> -<pre> <!-- progs/echo.go /package/ END --> -05 package main +<pre><!-- progs/echo.go /package/ $ +-->package main -07 import ( -08 "os" -09 "flag" // command line option parser -10 ) +import ( + "os" + "flag" // command line option parser +) -12 var omitNewline = flag.Bool("n", false, "don't print final newline") +var omitNewline = flag.Bool("n", false, "don't print final newline") -14 const ( -15 Space = " " -16 Newline = "\n" -17 ) +const ( + Space = " " + Newline = "\n" +) -19 func main() { -20 flag.Parse() // Scans the arg list and sets up flags -21 var s string = "" -22 for i := 0; i < flag.NArg(); i++ { -23 if i > 0 { -24 s += Space -25 } -26 s += flag.Arg(i) -27 } -28 if !*omitNewline { -29 s += Newline -30 } -31 os.Stdout.WriteString(s) -32 } +func main() { + flag.Parse() // Scans the arg list and sets up flags + var s string = "" + for i := 0; i < flag.NArg(); i++ { + if i > 0 { + s += Space + } + s += flag.Arg(i) + } + if !*omitNewline { + s += Newline + } + os.Stdout.WriteString(s) +} </pre> <p> 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> (not used yet) also introduce declarations, as does <code>import</code>. Notice that we can group declarations of the same sort into -parenthesized lists, one item per line, as on lines 7-10 and 14-17. +parenthesized lists, one item per line, as in the <code>import</code> and <code>const</code> clauses here. But it's not necessary to do so; we could have said <p> <pre> - const Space = " " - const Newline = "\n" +const Space = " " +const Newline = "\n" </pre> <p> This program imports the <code>"os"</code> package to access its <code>Stdout</code> variable, of type @@ -186,7 +186,7 @@ string variable we will use to build the output. The declaration statement has the form <p> <pre> - var s string = "" +var s string = "" </pre> <p> This is the <code>var</code> keyword, followed by the name of the variable, followed by @@ -197,20 +197,20 @@ string constant is of type string, we don't have to tell the compiler that. We could write <p> <pre> - var s = "" +var s = "" </pre> <p> or we could go even shorter and write the idiom <p> <pre> - s := "" +s := "" </pre> <p> The <code>:=</code> operator is used a lot in Go to represent an initializing declaration. There's one in the <code>for</code> clause on the next line: <p> -<pre> <!-- progs/echo.go /for/ --> -22 for i := 0; i < flag.NArg(); i++ { +<pre><!-- progs/echo.go /for/ +--> for i := 0; i < flag.NArg(); i++ { </pre> <p> The <code>flag</code> package has parsed the arguments and left the non-flag arguments @@ -231,7 +231,7 @@ It's defined that way. Falling off the end of <code>main.main</code> means ''success''; if you want to signal an erroneous return, call <p> <pre> - os.Exit(1) +os.Exit(1) </pre> <p> The <code>os</code> package contains other essentials for getting @@ -259,20 +259,20 @@ Once you've built a string <i>value</i>, you can't change it, although of course you can change a string <i>variable</i> simply by reassigning it. This snippet from <code>strings.go</code> is legal code: <p> -<pre> <!-- progs/strings.go /hello/ /ciao/ --> -10 s := "hello" -11 if s[1] != 'e' { os.Exit(1) } -12 s = "good bye" -13 var p *string = &s -14 *p = "ciao" +<pre><!-- progs/strings.go /hello/ /ciao/ +--> s := "hello" + if s[1] != 'e' { os.Exit(1) } + s = "good bye" + var p *string = &s + *p = "ciao" </pre> <p> However the following statements are illegal because they would modify a <code>string</code> value: <p> <pre> - s[0] = 'x' - (*p)[1] = 'y' +s[0] = 'x' +(*p)[1] = 'y' </pre> <p> In C++ terms, Go strings are a bit like <code>const strings</code>, while pointers @@ -284,7 +284,7 @@ read on. Arrays are declared like this: <p> <pre> - var arrayOfInt [10]int +var arrayOfInt [10]int </pre> <p> Arrays, like strings, are values, but they are mutable. This differs @@ -315,7 +315,7 @@ expression formed from a type followed by a brace-bounded expression like this: <p> <pre> - [3]int{1,2,3} +[3]int{1,2,3} </pre> <p> In this case the constructor builds an array of 3 <code>ints</code>. @@ -330,14 +330,14 @@ will slice the whole array. <p> Using slices one can write this function (from <code>sum.go</code>): <p> -<pre> <!-- progs/sum.go /sum/ /^}/ --> -09 func sum(a []int) int { // returns an int -10 s := 0 -11 for i := 0; i < len(a); i++ { -12 s += a[i] -13 } -14 return s -15 } +<pre><!-- progs/sum.go /sum/ /^}/ +-->func sum(a []int) int { // returns an int + s := 0 + for i := 0; i < len(a); i++ { + s += a[i] + } + return s +} </pre> <p> Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it @@ -348,14 +348,14 @@ a simpler way in a moment) constructs an array and slices it: <p> <pre> - s := sum([3]int{1,2,3}[:]) +s := sum([3]int{1,2,3}[:]) </pre> <p> If you are creating a regular array but want the compiler to count the elements for you, use <code>...</code> as the array size: <p> <pre> - s := sum([...]int{1,2,3}[:]) +s := sum([...]int{1,2,3}[:]) </pre> <p> That's fussier than necessary, though. @@ -363,13 +363,13 @@ In practice, unless you're meticulous about storage layout within a data structure, a slice itself—using empty brackets with no size—is all you need: <p> <pre> - s := sum([]int{1,2,3}) +s := sum([]int{1,2,3}) </pre> <p> There are also maps, which you can initialize like this: <p> <pre> - m := map[string]int{"one":1 , "two":2} +m := map[string]int{"one":1 , "two":2} </pre> <p> The built-in function <code>len</code>, which returns number of elements, @@ -380,13 +380,13 @@ By the way, another thing that works on strings, arrays, slices, maps and channels is the <code>range</code> clause on <code>for</code> loops. Instead of writing <p> <pre> - for i := 0; i < len(a); i++ { ... } +for i := 0; i < len(a); i++ { ... } </pre> <p> to loop over the elements of a slice (or map or ...) , we could write <p> <pre> - for i, v := range a { ... } +for i, v := range a { ... } </pre> <p> This assigns <code>i</code> to the index and <code>v</code> to the value of the successive @@ -404,14 +404,14 @@ To allocate a new variable, use the built-in function <code>new</code>, which returns a pointer to the allocated storage. <p> <pre> - type T struct { a, b int } - var t *T = new(T) +type T struct { a, b int } +var t *T = new(T) </pre> <p> or the more idiomatic <p> <pre> - t := new(T) +t := new(T) </pre> <p> Some types—maps, slices, and channels (see below)—have reference semantics. @@ -420,14 +420,14 @@ referencing the same underlying data will see the modification. For these three types you want to use the built-in function <code>make</code>: <p> <pre> - m := make(map[string]int) +m := make(map[string]int) </pre> <p> This statement initializes a new map ready to store entries. If you just declare the map, as in <p> <pre> - var m map[string]int +var m map[string]int </pre> <p> it creates a <code>nil</code> reference that cannot hold anything. To use the map, @@ -448,20 +448,20 @@ can overflow only when they are assigned to an integer variable with too little precision to represent the value. <p> <pre> - const hardEight = (1 << 100) >> 97 // legal +const hardEight = (1 << 100) >> 97 // legal </pre> <p> There are nuances that deserve redirection to the legalese of the language specification but here are some illustrative examples: <p> <pre> - var a uint64 = 0 // a has type uint64, value 0 - a := uint64(0) // equivalent; uses a "conversion" - i := 0x1234 // i gets default type: int - var j int = 1e6 // legal - 1000000 is representable in an int - x := 1.5 // a float64, the default type for floating constants - i3div2 := 3/2 // integer division - result is 1 - f3div2 := 3./2. // floating-point division - result is 1.5 +var a uint64 = 0 // a has type uint64, value 0 +a := uint64(0) // equivalent; uses a "conversion" +i := 0x1234 // i gets default type: int +var j int = 1e6 // legal - 1000000 is representable in an int +x := 1.5 // a float64, the default type for floating constants +i3div2 := 3/2 // integer division - result is 1 +f3div2 := 3./2. // floating-point division - result is 1.5 </pre> <p> Conversions only work for simple cases such as converting <code>ints</code> of one @@ -476,18 +476,18 @@ assigned to a variable. Next we'll look at a simple package for doing file I/O with an open/close/read/write interface. Here's the start of <code>file.go</code>: <p> -<pre> <!-- progs/file.go /package/ /^}/ --> -05 package file +<pre><!-- progs/file.go /package/ /^}/ +-->package file -07 import ( -08 "os" -09 "syscall" -10 ) +import ( + "os" + "syscall" +) -12 type File struct { -13 fd int // file descriptor number -14 name string // file name at Open time -15 } +type File struct { + fd int // file descriptor number + name string // file name at Open time +} </pre> <p> The first few lines declare the name of the @@ -518,13 +518,13 @@ will soon give it some exported, upper-case methods. <p> First, though, here is a factory to create a <code>File</code>: <p> -<pre> <!-- progs/file.go /newFile/ /^}/ --> -17 func newFile(fd int, name string) *File { -18 if fd < 0 { -19 return nil -20 } -21 return &File{fd, name} -22 } +<pre><!-- progs/file.go /newFile/ /^}/ +-->func newFile(fd int, name string) *File { + if fd < 0 { + return nil + } + return &File{fd, name} +} </pre> <p> This returns a pointer to a new <code>File</code> structure with the file descriptor and name @@ -533,10 +533,10 @@ the ones used to build maps and arrays, to construct a new heap-allocated object. We could write <p> <pre> - n := new(File) - n.fd = fd - n.name = name - return n +n := new(File) +n.fd = fd +n.name = name +return n </pre> <p> but for simple structures like <code>File</code> it's easier to return the address of a @@ -544,25 +544,26 @@ composite literal, as is done here on line 21. <p> We can use the factory to construct some familiar, exported variables of type <code>*File</code>: <p> -<pre> <!-- progs/file.go /var/ /^.$/ --> -24 var ( -25 Stdin = newFile(syscall.Stdin, "/dev/stdin") -26 Stdout = newFile(syscall.Stdout, "/dev/stdout") -27 Stderr = newFile(syscall.Stderr, "/dev/stderr") -28 ) +<pre><!-- progs/file.go /var/ /^.$/ +-->var ( + Stdin = newFile(syscall.Stdin, "/dev/stdin") + Stdout = newFile(syscall.Stdout, "/dev/stdout") + Stderr = newFile(syscall.Stderr, "/dev/stderr") +) + </pre> <p> 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): <p> -<pre> <!-- progs/file.go /func.OpenFile/ /^}/ --> -30 func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) { -31 r, e := syscall.Open(name, mode, perm) -32 if e != 0 { -33 err = os.Errno(e) -34 } -35 return newFile(r, name), err -36 } +<pre><!-- progs/file.go /func.OpenFile/ /^}/ +-->func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) { + r, e := syscall.Open(name, mode, perm) + if e != 0 { + err = os.Errno(e) + } + return newFile(r, name), err +} </pre> <p> There are a number of new things in these few lines. First, <code>OpenFile</code> returns @@ -593,23 +594,23 @@ the implementation of our <code>Open</code> and <code>Create</code>; they're tri wrappers that eliminate common errors by capturing the tricky standard arguments to open and, especially, to create a file: <p> -<pre> <!-- progs/file.go /^const/ /^}/ --> -38 const ( -39 O_RDONLY = syscall.O_RDONLY -40 O_RDWR = syscall.O_RDWR -41 O_CREATE = syscall.O_CREAT -42 O_TRUNC = syscall.O_TRUNC -43 ) +<pre><!-- progs/file.go /^const/ /^}/ +-->const ( + O_RDONLY = syscall.O_RDONLY + O_RDWR = syscall.O_RDWR + O_CREATE = syscall.O_CREAT + O_TRUNC = syscall.O_TRUNC +) -45 func Open(name string) (file *File, err os.Error) { -46 return OpenFile(name, O_RDONLY, 0) -47 } +func Open(name string) (file *File, err os.Error) { + return OpenFile(name, O_RDONLY, 0) +} </pre> <p> -<pre> <!-- progs/file.go /func.Create/ /^}/ --> -49 func Create(name string) (file *File, err os.Error) { -50 return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666) -51 } +<pre><!-- progs/file.go /func.Create/ /^}/ +-->func Create(name string) (file *File, err os.Error) { + return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666) +} </pre> <p> Back to our main story. @@ -619,44 +620,44 @@ of that type, placed in parentheses before the function name. Here are some methods for <code>*File</code>, each of which declares a receiver variable <code>file</code>. <p> -<pre> <!-- progs/file.go /Close/ END --> -53 func (file *File) Close() os.Error { -54 if file == nil { -55 return os.EINVAL -56 } -57 e := syscall.Close(file.fd) -58 file.fd = -1 // so it can't be closed again -59 if e != 0 { -60 return os.Errno(e) -61 } -62 return nil -63 } +<pre><!-- progs/file.go /Close/ $ +-->func (file *File) Close() os.Error { + if file == nil { + return os.EINVAL + } + e := syscall.Close(file.fd) + file.fd = -1 // so it can't be closed again + if e != 0 { + return os.Errno(e) + } + return nil +} -65 func (file *File) Read(b []byte) (ret int, err os.Error) { -66 if file == nil { -67 return -1, os.EINVAL -68 } -69 r, e := syscall.Read(file.fd, b) -70 if e != 0 { -71 err = os.Errno(e) -72 } -73 return int(r), err -74 } +func (file *File) Read(b []byte) (ret int, err os.Error) { + if file == nil { + return -1, os.EINVAL + } + r, e := syscall.Read(file.fd, b) + if e != 0 { + err = os.Errno(e) + } + return int(r), err +} -76 func (file *File) Write(b []byte) (ret int, err os.Error) { -77 if file == nil { -78 return -1, os.EINVAL -79 } -80 r, e := syscall.Write(file.fd, b) -81 if e != 0 { -82 err = os.Errno(e) -83 } -84 return int(r), err -85 } +func (file *File) Write(b []byte) (ret int, err os.Error) { + if file == nil { + return -1, os.EINVAL + } + r, e := syscall.Write(file.fd, b) + if e != 0 { + err = os.Errno(e) + } + return int(r), err +} -87 func (file *File) String() string { -88 return file.name -89 } +func (file *File) String() string { + return file.name +} </pre> <p> There is no implicit <code>this</code> and the receiver variable must be used to access @@ -674,24 +675,24 @@ set of such error values. <p> We can now use our new package: <p> -<pre> <!-- progs/helloworld3.go /package/ END --> -05 package main +<pre><!-- progs/helloworld3.go /package/ $ +-->package main -07 import ( -08 "./file" -09 "fmt" -10 "os" -11 ) +import ( + "./file" + "fmt" + "os" +) -13 func main() { -14 hello := []byte("hello, world\n") -15 file.Stdout.Write(hello) -16 f, err := file.Open("/does/not/exist") -17 if f == nil { -18 fmt.Printf("can't open file; err=%s\n", err.String()) -19 os.Exit(1) -20 } -21 } +func main() { + hello := []byte("hello, world\n") + file.Stdout.Write(hello) + f, err := file.Open("/does/not/exist") + if f == nil { + fmt.Printf("can't open file; err=%s\n", err.String()) + os.Exit(1) + } +} </pre> <p> The ''<code>./</code>'' in the import of ''<code>./file</code>'' tells the compiler @@ -703,13 +704,13 @@ package.) Now we can compile and run the program. On Unix, this would be the result: <p> <pre> - $ 6g file.go # compile file package - $ 6g helloworld3.go # compile main package - $ 6l -o helloworld3 helloworld3.6 # link - no need to mention "file" - $ helloworld3 - hello, world - can't open file; err=No such file or directory - $ +$ 6g file.go # compile file package +$ 6g helloworld3.go # compile main package +$ 6l -o helloworld3 helloworld3.6 # link - no need to mention "file" +$ helloworld3 +hello, world +can't open file; err=No such file or directory +$ </pre> <p> <h2>Rotting cats</h2> @@ -717,56 +718,56 @@ Now we can compile and run the program. On Unix, this would be the result: Building on the <code>file</code> package, here's a simple version of the Unix utility <code>cat(1)</code>, <code>progs/cat.go</code>: <p> -<pre> <!-- progs/cat.go /package/ END --> -05 package main +<pre><!-- progs/cat.go /package/ $ +-->package main -07 import ( -08 "./file" -09 "flag" -10 "fmt" -11 "os" -12 ) +import ( + "./file" + "flag" + "fmt" + "os" +) -14 func cat(f *file.File) { -15 const NBUF = 512 -16 var buf [NBUF]byte -17 for { -18 switch nr, er := f.Read(buf[:]); true { -19 case nr < 0: -20 fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String()) -21 os.Exit(1) -22 case nr == 0: // EOF -23 return -24 case nr > 0: -25 if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr { -26 fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String()) -27 os.Exit(1) -28 } -29 } -30 } -31 } +func cat(f *file.File) { + const NBUF = 512 + var buf [NBUF]byte + for { + switch nr, er := f.Read(buf[:]); true { + case nr < 0: + fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String()) + os.Exit(1) + case nr == 0: // EOF + return + case nr > 0: + if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr { + fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String()) + os.Exit(1) + } + } + } +} -33 func main() { -34 flag.Parse() // Scans the arg list and sets up flags -35 if flag.NArg() == 0 { -36 cat(file.Stdin) -37 } -38 for i := 0; i < flag.NArg(); i++ { -39 f, err := file.Open(flag.Arg(i)) -40 if f == nil { -41 fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err) -42 os.Exit(1) -43 } -44 cat(f) -45 f.Close() -46 } -47 } +func main() { + flag.Parse() // Scans the arg list and sets up flags + if flag.NArg() == 0 { + cat(file.Stdin) + } + for i := 0; i < flag.NArg(); i++ { + f, err := file.Open(flag.Arg(i)) + if f == nil { + fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err) + os.Exit(1) + } + cat(f) + f.Close() + } +} </pre> <p> 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 -initialization statement. The <code>switch</code> on line 18 uses one to create variables -<code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>. (The <code>if</code> on line 25 +initialization statement. The <code>switch</code> statement in <code>cat</code> uses one to create variables +<code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>. (The <code>if</code> a few lines later has the same idea.) The <code>switch</code> statement is general: it evaluates the cases from top to bottom looking for the first case that matches the value; the case expressions don't need to be constants or even integers, as long as @@ -778,7 +779,7 @@ in a <code>for</code> statement, a missing value means <code>true</code>. In fa is a form of <code>if-else</code> chain. While we're here, it should be mentioned that in <code>switch</code> statements each <code>case</code> has an implicit <code>break</code>. <p> -Line 25 calls <code>Write</code> by slicing the incoming buffer, which is itself a slice. +The argument to <code>file.Stdout.Write</code> is created by slicing the array <code>buf</code>. Slices provide the standard Go way to handle I/O buffers. <p> Now let's make a variant of <code>cat</code> that optionally does <code>rot13</code> on its input. @@ -789,11 +790,11 @@ The <code>cat</code> subroutine uses only two methods of <code>f</code>: <code>R so let's start by defining an interface that has exactly those two methods. Here is code from <code>progs/cat_rot13.go</code>: <p> -<pre> <!-- progs/cat_rot13.go /type.reader/ /^}/ --> -26 type reader interface { -27 Read(b []byte) (ret int, err os.Error) -28 String() string -29 } +<pre><!-- progs/cat_rot13.go /type.reader/ /^}/ +-->type reader interface { + Read(b []byte) (ret int, err os.Error) + String() string +} </pre> <p> Any type that has the two methods of <code>reader</code>—regardless of whatever @@ -806,68 +807,68 @@ existing <code>reader</code> and does <code>rot13</code> on the data. To do this the type and implement the methods and with no other bookkeeping, we have a second implementation of the <code>reader</code> interface. <p> -<pre> <!-- progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/ --> -31 type rotate13 struct { -32 source reader -33 } +<pre><!-- progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/ +-->type rotate13 struct { + source reader +} -35 func newRotate13(source reader) *rotate13 { -36 return &rotate13{source} -37 } +func newRotate13(source reader) *rotate13 { + return &rotate13{source} +} -39 func (r13 *rotate13) Read(b []byte) (ret int, err os.Error) { -40 r, e := r13.source.Read(b) -41 for i := 0; i < r; i++ { -42 b[i] = rot13(b[i]) -43 } -44 return r, e -45 } +func (r13 *rotate13) Read(b []byte) (ret int, err os.Error) { + r, e := r13.source.Read(b) + for i := 0; i < r; i++ { + b[i] = rot13(b[i]) + } + return r, e +} -47 func (r13 *rotate13) String() string { -48 return r13.source.String() -49 } -50 // end of rotate13 implementation +func (r13 *rotate13) String() string { + return r13.source.String() +} +// end of rotate13 implementation </pre> <p> -(The <code>rot13</code> function called on line 42 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> To use the new feature, we define a flag: <p> -<pre> <!-- progs/cat_rot13.go /rot13Flag/ --> -14 var rot13Flag = flag.Bool("rot13", false, "rot13 the input") +<pre><!-- progs/cat_rot13.go /rot13Flag/ +-->var rot13Flag = flag.Bool("rot13", false, "rot13 the input") </pre> <p> and use it from within a mostly unchanged <code>cat</code> function: <p> -<pre> <!-- progs/cat_rot13.go /func.cat/ /^}/ --> -52 func cat(r reader) { -53 const NBUF = 512 -54 var buf [NBUF]byte +<pre><!-- progs/cat_rot13.go /func.cat/ /^}/ +-->func cat(r reader) { + const NBUF = 512 + var buf [NBUF]byte -56 if *rot13Flag { -57 r = newRotate13(r) -58 } -59 for { -60 switch nr, er := r.Read(buf[:]); { -61 case nr < 0: -62 fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String()) -63 os.Exit(1) -64 case nr == 0: // EOF -65 return -66 case nr > 0: -67 nw, ew := file.Stdout.Write(buf[0:nr]) -68 if nw != nr { -69 fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String()) -70 os.Exit(1) -71 } -72 } -73 } -74 } + if *rot13Flag { + r = newRotate13(r) + } + for { + switch nr, er := r.Read(buf[:]); { + case nr < 0: + fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String()) + os.Exit(1) + case nr == 0: // EOF + return + case nr > 0: + nw, ew := file.Stdout.Write(buf[0:nr]) + if nw != nr { + fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String()) + os.Exit(1) + } + } + } +} </pre> <p> (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.) -Lines 56 through 58 set it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code> +The <code>if</code> at the top of <code>cat</code> sets it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code> we received into a <code>rotate13</code> and proceed. Note that the interface variables are values, not pointers: the argument is of type <code>reader</code>, not <code>*reader</code>, even though under the covers it holds a pointer to a <code>struct</code>. @@ -875,11 +876,11 @@ even though under the covers it holds a pointer to a <code>struct</code>. Here it is in action: <p> <pre> - $ echo abcdefghijklmnopqrstuvwxyz | ./cat - abcdefghijklmnopqrstuvwxyz - $ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13 - nopqrstuvwxyzabcdefghijklm - $ +$ echo abcdefghijklmnopqrstuvwxyz | ./cat +abcdefghijklmnopqrstuvwxyz +$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13 +nopqrstuvwxyzabcdefghijklm +$ </pre> <p> Fans of dependency injection may take cheer from how easily interfaces @@ -895,7 +896,7 @@ implement a <code>writer</code>, or any other interface built from its methods t fits the current situation. Consider the <i>empty interface</i> <p> <pre> - type Empty interface {} +type Empty interface {} </pre> <p> <i>Every</i> type implements the empty interface, which makes it @@ -910,36 +911,36 @@ same interface variable. <p> As an example, consider this simple sort algorithm taken from <code>progs/sort.go</code>: <p> -<pre> <!-- progs/sort.go /func.Sort/ /^}/ --> -13 func Sort(data Interface) { -14 for i := 1; i < data.Len(); i++ { -15 for j := i; j > 0 && data.Less(j, j-1); j-- { -16 data.Swap(j, j-1) -17 } -18 } -19 } +<pre><!-- progs/sort.go /func.Sort/ /^}/ +-->func Sort(data Interface) { + for i := 1; i < data.Len(); i++ { + for j := i; j > 0 && data.Less(j, j-1); j-- { + data.Swap(j, j-1) + } + } +} </pre> <p> The code needs only three methods, which we wrap into sort's <code>Interface</code>: <p> -<pre> <!-- progs/sort.go /interface/ /^}/ --> -07 type Interface interface { -08 Len() int -09 Less(i, j int) bool -10 Swap(i, j int) -11 } +<pre><!-- progs/sort.go /interface/ /^}/ +-->type Interface interface { + Len() int + Less(i, j int) bool + Swap(i, j int) +} </pre> <p> 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 arrays of integers, strings, etc.; here's the code for arrays of <code>int</code> <p> -<pre> <!-- progs/sort.go /type.*IntArray/ /Swap/ --> -33 type IntArray []int +<pre><!-- progs/sort.go /type.*IntSlice/ /Swap/ +-->type IntSlice []int -35 func (p IntArray) Len() int { return len(p) } -36 func (p IntArray) Less(i, j int) bool { return p[i] < p[j] } -37 func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p IntSlice) Len() int { return len(p) } +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] } </pre> <p> Here we see methods defined for non-<code>struct</code> types. You can define methods @@ -949,34 +950,34 @@ And now a routine to test it out, from <code>progs/sortmain.go</code>. This uses a function in the <code>sort</code> package, omitted here for brevity, to test that the result is sorted. <p> -<pre> <!-- progs/sortmain.go /func.ints/ /^}/ --> -12 func ints() { -13 data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} -14 a := sort.IntArray(data) -15 sort.Sort(a) -16 if !sort.IsSorted(a) { -17 panic("fail") -18 } -19 } +<pre><!-- progs/sortmain.go /func.ints/ /^}/ +-->func ints() { + data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} + a := sort.IntSlice(data) + sort.Sort(a) + if !sort.IsSorted(a) { + panic("fail") + } +} </pre> <p> 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: <p> -<pre> <!-- progs/sortmain.go /type.day/ /Swap/ --> -30 type day struct { -31 num int -32 shortName string -33 longName string -34 } +<pre><!-- progs/sortmain.go /type.day/ /Swap/ +-->type day struct { + num int + shortName string + longName string +} -36 type dayArray struct { -37 data []*day -38 } +type dayArray struct { + data []*day +} -40 func (p *dayArray) Len() int { return len(p.data) } -41 func (p *dayArray) Less(i, j int) bool { return p.data[i].num < p.data[j].num } -42 func (p *dayArray) Swap(i, j int) { p.data[i], p.data[j] = p.data[j], p.data[i] } +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) Swap(i, j int) { p.data[i], p.data[j] = p.data[j], p.data[i] } </pre> <p> <p> @@ -990,7 +991,7 @@ implements <code>Printf</code>, <code>Fprintf</code>, and so on. Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature: <p> <pre> - Printf(format string, v ...interface{}) (n int, errno os.Error) +Printf(format string, v ...interface{}) (n int, errno os.Error) </pre> <p> The token <code>...</code> introduces a variable-length argument list that in C would @@ -1011,34 +1012,34 @@ argument. It's easier in many cases in Go. Instead of <code>%llud</code> you can just say <code>%d</code>; <code>Printf</code> knows the size and signedness of the integer and can do the right thing for you. The snippet <p> -<pre> <!-- progs/print.go NR==10 NR==11 --> -10 var u64 uint64 = 1<<64-1 -11 fmt.Printf("%d %d\n", u64, int64(u64)) +<pre><!-- progs/print.go 10 11 +--> var u64 uint64 = 1<<64-1 + fmt.Printf("%d %d\n", u64, int64(u64)) </pre> <p> prints <p> <pre> - 18446744073709551615 -1 +18446744073709551615 -1 </pre> <p> In fact, if you're lazy the format <code>%v</code> will print, in a simple appropriate style, any value, even an array or structure. The output of <p> -<pre> <!-- progs/print.go NR==14 NR==20 --> -14 type T struct { -15 a int -16 b string -17 } -18 t := T{77, "Sunset Strip"} -19 a := []int{1, 2, 3, 4} -20 fmt.Printf("%v %v %v\n", u64, t, a) +<pre><!-- progs/print.go 14 20 +--> type T struct { + a int + b string + } + t := T{77, "Sunset Strip"} + a := []int{1, 2, 3, 4} + fmt.Printf("%v %v %v\n", u64, t, a) </pre> <p> is <p> <pre> - 18446744073709551615 {77 Sunset Strip} [1 2 3 4] +18446744073709551615 {77 Sunset Strip} [1 2 3 4] </pre> <p> You can drop the formatting altogether if you use <code>Print</code> or <code>Println</code> @@ -1048,9 +1049,9 @@ of <code>%v</code> while <code>Println</code> inserts spaces between arguments and adds a newline. The output of each of these two lines is identical to that of the <code>Printf</code> call above. <p> -<pre> <!-- progs/print.go NR==21 NR==22 --> -21 fmt.Print(u64, " ", t, " ", a, "\n") -22 fmt.Println(u64, t, a) +<pre><!-- progs/print.go 21 22 +--> fmt.Print(u64, " ", t, " ", a, "\n") + fmt.Println(u64, t, a) </pre> <p> If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format, @@ -1059,27 +1060,27 @@ routines will examine the value to inquire whether it implements the method and if so, use it rather than some other formatting. Here's a simple example. <p> -<pre> <!-- progs/print_string.go NR==9 END --> -09 type testType struct { -10 a int -11 b string -12 } +<pre><!-- progs/print_string.go 9 $ +-->type testType struct { + a int + b string +} -14 func (t *testType) String() string { -15 return fmt.Sprint(t.a) + " " + t.b -16 } +func (t *testType) String() string { + return fmt.Sprint(t.a) + " " + t.b +} -18 func main() { -19 t := &testType{77, "Sunset Strip"} -20 fmt.Println(t) -21 } +func main() { + t := &testType{77, "Sunset Strip"} + fmt.Println(t) +} </pre> <p> Since <code>*testType</code> has a <code>String</code> method, the default formatter for that type will use it and produce the output <p> <pre> - 77 Sunset Strip +77 Sunset Strip </pre> <p> Observe that the <code>String</code> method calls <code>Sprint</code> (the obvious Go @@ -1101,18 +1102,18 @@ Schematically, given a value <code>v</code>, it does this: <p> <p> <pre> - type Stringer interface { - String() string - } +type Stringer interface { + String() string +} </pre> <p> <pre> - s, ok := v.(Stringer) // Test whether v implements "String()" - if ok { - result = s.String() - } else { - result = defaultOutput(v) - } +s, ok := v.(Stringer) // Test whether v implements "String()" +if ok { + result = s.String() +} else { + result = defaultOutput(v) +} </pre> <p> The code uses a ``type assertion'' (<code>v.(Stringer)</code>) to test if the value stored in @@ -1133,9 +1134,9 @@ not a file. Instead, it is a variable of type <code>io.Writer</code>, which is interface type defined in the <code>io</code> library: <p> <pre> - type Writer interface { - Write(p []byte) (n int, err os.Error) - } +type Writer interface { + Write(p []byte) (n int, err os.Error) +} </pre> <p> (This interface is another conventional name, this time for <code>Write</code>; there are also @@ -1178,13 +1179,13 @@ coordinates the communication; as with maps and slices, use <p> Here is the first function in <code>progs/sieve.go</code>: <p> -<pre> <!-- progs/sieve.go /Send/ /^}/ --> -09 // Send the sequence 2, 3, 4, ... to channel 'ch'. -10 func generate(ch chan int) { -11 for i := 2; ; i++ { -12 ch <- i // Send 'i' to channel 'ch'. -13 } -14 } +<pre><!-- progs/sieve.go /Send/ /^}/ +-->// Send the sequence 2, 3, 4, ... to channel 'ch'. +func generate(ch chan int) { + for i := 2; ; i++ { + ch <- i // Send 'i' to channel 'ch'. + } +} </pre> <p> The <code>generate</code> function sends the sequence 2, 3, 4, 5, ... to its @@ -1197,17 +1198,17 @@ channel, and a prime number. It copies values from the input to the output, discarding anything divisible by the prime. The unary communications operator <code><-</code> (receive) retrieves the next value on the channel. <p> -<pre> <!-- progs/sieve.go /Copy.the/ /^}/ --> -16 // Copy the values from channel 'in' to channel 'out', -17 // removing those divisible by 'prime'. -18 func filter(in, out chan int, prime int) { -19 for { -20 i := <-in // Receive value of new variable 'i' from 'in'. -21 if i % prime != 0 { -22 out <- i // Send 'i' to channel 'out'. -23 } -24 } -25 } +<pre><!-- progs/sieve.go /Copy.the/ /^}/ +-->// Copy the values from channel 'in' to channel 'out', +// removing those divisible by 'prime'. +func filter(in, out chan int, prime int) { + for { + i := <-in // Receive value of new variable 'i' from 'in'. + if i % prime != 0 { + out <- i // Send 'i' to channel 'out'. + } + } +} </pre> <p> The generator and filters execute concurrently. Go has @@ -1219,37 +1220,37 @@ this starts the function running in parallel with the current computation but in the same address space: <p> <pre> - go sum(hugeArray) // calculate sum in the background +go sum(hugeArray) // calculate sum in the background </pre> <p> If you want to know when the calculation is done, pass a channel on which it can report back: <p> <pre> - ch := make(chan int) - go sum(hugeArray, ch) - // ... do something else for a while - result := <-ch // wait for, and retrieve, result +ch := make(chan int) +go sum(hugeArray, ch) +// ... do something else for a while +result := <-ch // wait for, and retrieve, result </pre> <p> Back to our prime sieve. Here's how the sieve pipeline is stitched together: <p> -<pre> <!-- progs/sieve.go /func.main/ /^}/ --> -28 func main() { -29 ch := make(chan int) // Create a new channel. -30 go generate(ch) // Start generate() as a goroutine. -31 for i := 0; i < 100; i++ { // Print the first hundred primes. -32 prime := <-ch -33 fmt.Println(prime) -34 ch1 := make(chan int) -35 go filter(ch, ch1, prime) -36 ch = ch1 -37 } -38 } -</pre> -<p> -Line 29 creates the initial channel to pass to <code>generate</code>, which it +<pre><!-- progs/sieve.go /func.main/ /^}/ +-->func main() { + ch := make(chan int) // Create a new channel. + go generate(ch) // Start generate() as a goroutine. + for i := 0; i < 100; i++ { // Print the first hundred primes. + prime := <-ch + fmt.Println(prime) + ch1 := make(chan int) + go filter(ch, ch1, prime) + ch = ch1 + } +} +</pre> +<p> +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> is added to the pipeline and <i>its</i> output becomes the new value of <code>ch</code>. @@ -1258,16 +1259,16 @@ The sieve program can be tweaked to use a pattern common in this style of programming. Here is a variant version of <code>generate</code>, from <code>progs/sieve1.go</code>: <p> -<pre> <!-- progs/sieve1.go /func.generate/ /^}/ --> -10 func generate() chan int { -11 ch := make(chan int) -12 go func(){ -13 for i := 2; ; i++ { -14 ch <- i -15 } -16 }() -17 return ch -18 } +<pre><!-- progs/sieve1.go /func.generate/ /^}/ +-->func generate() chan int { + ch := make(chan int) + go func(){ + for i := 2; ; i++ { + ch <- i + } + }() + return ch +} </pre> <p> This version does all the setup internally. It creates the output @@ -1275,54 +1276,54 @@ channel, launches a goroutine running a function literal, and returns the channel to the caller. It is a factory for concurrent execution, starting the goroutine and returning its connection. <p> -The function literal notation (lines 12-16) allows us to construct an +The function literal notation used in the <code>go</code> statement allows us to construct an anonymous function and invoke it on the spot. Notice that the local variable <code>ch</code> is available to the function literal and lives on even after <code>generate</code> returns. <p> The same change can be made to <code>filter</code>: <p> -<pre> <!-- progs/sieve1.go /func.filter/ /^}/ --> -21 func filter(in chan int, prime int) chan int { -22 out := make(chan int) -23 go func() { -24 for { -25 if i := <-in; i % prime != 0 { -26 out <- i -27 } -28 } -29 }() -30 return out -31 } +<pre><!-- progs/sieve1.go /func.filter/ /^}/ +-->func filter(in chan int, prime int) chan int { + out := make(chan int) + go func() { + for { + if i := <-in; i % prime != 0 { + out <- i + } + } + }() + return out +} </pre> <p> 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: <p> -<pre> <!-- progs/sieve1.go /func.sieve/ /^}/ --> -33 func sieve() chan int { -34 out := make(chan int) -35 go func() { -36 ch := generate() -37 for { -38 prime := <-ch -39 out <- prime -40 ch = filter(ch, prime) -41 } -42 }() -43 return out -44 } +<pre><!-- progs/sieve1.go /func.sieve/ /^}/ +-->func sieve() chan int { + out := make(chan int) + go func() { + ch := generate() + for { + prime := <-ch + out <- prime + ch = filter(ch, prime) + } + }() + return out +} </pre> <p> Now <code>main</code>'s interface to the prime sieve is a channel of primes: <p> -<pre> <!-- progs/sieve1.go /func.main/ /^}/ --> -46 func main() { -47 primes := sieve() -48 for i := 0; i < 100; i++ { // Print the first hundred primes. -49 fmt.Println(<-primes) -50 } -51 } +<pre><!-- progs/sieve1.go /func.main/ /^}/ +-->func main() { + primes := sieve() + for i := 0; i < 100; i++ { // Print the first hundred primes. + fmt.Println(<-primes) + } +} </pre> <p> <h2>Multiplexing</h2> @@ -1334,102 +1335,102 @@ A realistic client-server program is a lot of code, so here is a very simple sub to illustrate the idea. It starts by defining a <code>request</code> type, which embeds a channel that will be used for the reply. <p> -<pre> <!-- progs/server.go /type.request/ /^}/ --> -09 type request struct { -10 a, b int -11 replyc chan int -12 } +<pre><!-- progs/server.go /type.request/ /^}/ +-->type request struct { + a, b int + replyc chan int +} </pre> <p> 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: <p> -<pre> <!-- progs/server.go /type.binOp/ /^}/ --> -14 type binOp func(a, b int) int +<pre><!-- progs/server.go /type.binOp/ /^}/ +-->type binOp func(a, b int) int -16 func run(op binOp, req *request) { -17 reply := op(req.a, req.b) -18 req.replyc <- reply -19 } +func run(op binOp, req *request) { + reply := op(req.a, req.b) + req.replyc <- reply +} </pre> <p> -Line 14 defines the name <code>binOp</code> to be a function taking two integers and +The type declaration makes <code>binOp</code> represent a function taking two integers and returning a third. <p> The <code>server</code> routine loops forever, receiving requests and, to avoid blocking due to a long-running operation, starting a goroutine to do the actual work. <p> -<pre> <!-- progs/server.go /func.server/ /^}/ --> -21 func server(op binOp, service chan *request) { -22 for { -23 req := <-service -24 go run(op, req) // don't wait for it -25 } -26 } +<pre><!-- progs/server.go /func.server/ /^}/ +-->func server(op binOp, service chan *request) { + for { + req := <-service + go run(op, req) // don't wait for it + } +} </pre> <p> We construct a server in a familiar way, starting it and returning a channel connected to it: <p> -<pre> <!-- progs/server.go /func.startServer/ /^}/ --> -28 func startServer(op binOp) chan *request { -29 req := make(chan *request) -30 go server(op, req) -31 return req -32 } +<pre><!-- progs/server.go /func.startServer/ /^}/ +-->func startServer(op binOp) chan *request { + req := make(chan *request) + go server(op, req) + return req +} </pre> <p> Here's a simple test. It starts a server with an addition operator and sends out <code>N</code> requests without waiting for the replies. Only after all the requests are sent does it check the results. <p> -<pre> <!-- progs/server.go /func.main/ /^}/ --> -34 func main() { -35 adder := startServer(func(a, b int) int { return a + b }) -36 const N = 100 -37 var reqs [N]request -38 for i := 0; i < N; i++ { -39 req := &reqs[i] -40 req.a = i -41 req.b = i + N -42 req.replyc = make(chan int) -43 adder <- req -44 } -45 for i := N-1; i >= 0; i-- { // doesn't matter what order -46 if <-reqs[i].replyc != N + 2*i { -47 fmt.Println("fail at", i) -48 } -49 } -50 fmt.Println("done") -51 } +<pre><!-- progs/server.go /func.main/ /^}/ +-->func main() { + adder := startServer(func(a, b int) int { return a + b }) + const N = 100 + var reqs [N]request + for i := 0; i < N; i++ { + req := &reqs[i] + req.a = i + req.b = i + N + req.replyc = make(chan int) + adder <- req + } + for i := N-1; i >= 0; i-- { // doesn't matter what order + if <-reqs[i].replyc != N + 2*i { + fmt.Println("fail at", i) + } + } + fmt.Println("done") +} </pre> <p> 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, we can provide a second, <code>quit</code> channel to the server: <p> -<pre> <!-- progs/server1.go /func.startServer/ /^}/ --> -32 func startServer(op binOp) (service chan *request, quit chan bool) { -33 service = make(chan *request) -34 quit = make(chan bool) -35 go server(op, service, quit) -36 return service, quit -37 } +<pre><!-- progs/server1.go /func.startServer/ /^}/ +-->func startServer(op binOp) (service chan *request, quit chan bool) { + service = make(chan *request) + quit = make(chan bool) + go server(op, service, quit) + return service, quit +} </pre> <p> It passes the quit channel to the <code>server</code> function, which uses it like this: <p> -<pre> <!-- progs/server1.go /func.server/ /^}/ --> -21 func server(op binOp, service chan *request, quit chan bool) { -22 for { -23 select { -24 case req := <-service: -25 go run(op, req) // don't wait for it -26 case <-quit: -27 return -28 } -29 } -30 } +<pre><!-- progs/server1.go /func.server/ /^}/ +-->func server(op binOp, service chan *request, quit chan bool) { + for { + select { + case req := <-service: + go run(op, req) // don't wait for it + case <-quit: + return + } + } +} </pre> <p> Inside <code>server</code>, the <code>select</code> statement chooses which of the multiple communications @@ -1442,12 +1443,12 @@ returns, terminating its execution. All that's left is to strobe the <code>quit</code> channel at the end of main: <p> -<pre> <!-- progs/server1.go /adder,.quit/ --> -40 adder, quit := startServer(func(a, b int) int { return a + b }) +<pre><!-- progs/server1.go /adder,.quit/ +--> adder, quit := startServer(func(a, b int) int { return a + b }) </pre> ... -<pre> <!-- progs/server1.go /quit....true/ --> -55 quit <- true +<pre><!-- progs/server1.go /quit....true/ +--> quit <- true </pre> <p> There's a lot more to Go programming and concurrent programming in general but this |