Commit 83f0b718 authored by Rob Pike's avatar Rob Pike

fixups in the tutorial

also add a section about compiling programs because some found it surprising not to have one

R=rsc
CC=go-dev
http://go/go-review/1018011
parent dde666da
<!-- Let's Go --> <!-- Let's Go -->
<h2>Introduction</h2> <h2>Introduction</h2>
<p> <p>
This document is a tutorial introduction to the basics of the Go systems programming This document is a tutorial introduction to the basics of the Go programming
language, intended for programmers familiar with C or C++. It is not a comprehensive language, intended for programmers familiar with C or C++. It is not a comprehensive
guide to the language; at the moment the document closest to that is the guide to the language; at the moment the document closest to that is the
<a href='/doc/go_spec.html'>language specification.</a> <a href='/doc/go_spec.html'>language specification</a>.
After you've read this tutorial, you might want to look at
<a href='/doc/effective_go.html'>Effective Go</a>,
which digs deeper into how the language is used.
<p> <p>
The presentation proceeds through a series of modest programs to illustrate The presentation here proceeds through a series of modest programs to illustrate
key features of the language. All the programs work (at time of writing) and are key features of the language. All the programs work (at time of writing) and are
checked into the repository in the directory <a href='/doc/progs'><code>/doc/progs/</code></a>. checked into the repository in the directory <a href='/doc/progs'><code>/doc/progs/</code></a>.
<p> <p>
...@@ -48,6 +51,35 @@ The comment convention is the same as in C++: ...@@ -48,6 +51,35 @@ The comment convention is the same as in C++:
<p> <p>
Later we'll have much more to say about printing. Later we'll have much more to say about printing.
<p> <p>
<h2>Compiling</h2>
<p>
Go is a compiled language. At the moment there are two compilers.
<code>Gccgo</code> is a Go compiler that uses the GCC back end. There is also a
suite of compilers with different (and odd) names for each architecture:
<code>6g</code> for the 64-bit x86, <code>8g</code> for the 32-bit x86, and more. These
compilers run significantly faster but generate less efficient code
than <code>gccgo</code>. At the time of writing (late 2009), they also have
a more robust run-time system although <code>gccgo</code> is catching up.
<p>
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 こんにちは 世界
$
</pre>
<p>
With <code>gccgo</code> it looks a little more traditional.
<p>
<pre>
$ gccgo helloworld.go
$ a.out
Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
$
</pre>
<p>
<h2>Echo</h2> <h2>Echo</h2>
<p> <p>
Next up, here's a version of the Unix utility <code>echo(1)</code>: Next up, here's a version of the Unix utility <code>echo(1)</code>:
...@@ -63,8 +95,8 @@ Next up, here's a version of the Unix utility <code>echo(1)</code>: ...@@ -63,8 +95,8 @@ Next up, here's a version of the Unix utility <code>echo(1)</code>:
12 var n_flag = flag.Bool(&quot;n&quot;, false, &quot;don't print final newline&quot;) 12 var n_flag = flag.Bool(&quot;n&quot;, false, &quot;don't print final newline&quot;)
<p> <p>
14 const ( 14 const (
15 kSpace = &quot; &quot;; 15 Space = &quot; &quot;;
16 kNewline = &quot;\n&quot;; 16 Newline = &quot;\n&quot;;
17 ) 17 )
<p> <p>
19 func main() { 19 func main() {
...@@ -72,22 +104,22 @@ Next up, here's a version of the Unix utility <code>echo(1)</code>: ...@@ -72,22 +104,22 @@ Next up, here's a version of the Unix utility <code>echo(1)</code>:
21 var s string = &quot;&quot;; 21 var s string = &quot;&quot;;
22 for i := 0; i &lt; flag.NArg(); i++ { 22 for i := 0; i &lt; flag.NArg(); i++ {
23 if i &gt; 0 { 23 if i &gt; 0 {
24 s += kSpace 24 s += Space
25 } 25 }
26 s += flag.Arg(i) 26 s += flag.Arg(i)
27 } 27 }
28 if !*n_flag { 28 if !*n_flag {
29 s += kNewline 29 s += Newline
30 } 30 }
31 os.Stdout.WriteString(s); 31 os.Stdout.WriteString(s);
32 } 32 }
</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> introducing 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>
(not used yet) also introduce declarations, as does <code>import</code>. (not used yet) also introduce declarations, as does <code>import</code>.
Notice that we can group declarations of the same sort into Notice that we can group declarations of the same sort into
parenthesized, semicolon-separated lists if we want, as on lines 4-10 and 14-17. parenthesized, semicolon-separated lists if we want, as on lines 7-10 and 14-17.
But it's not necessary to do so; we could have said But it's not necessary to do so; we could have said
<p> <p>
<pre> <pre>
...@@ -168,7 +200,7 @@ Later examples will show some other ways <code>for</code> can be written. ...@@ -168,7 +200,7 @@ Later examples will show some other ways <code>for</code> can be written.
<p> <p>
The body of the loop builds up the string <code>s</code> by appending (using <code>+=</code>) The body of the loop builds up the string <code>s</code> by appending (using <code>+=</code>)
the flags and separating spaces. After the loop, if the <code>-n</code> flag is not the flags and separating spaces. After the loop, if the <code>-n</code> flag is not
set, it appends a newline, and then writes the result. set, the program appends a newline. Finally, it writes the result.
<p> <p>
Notice that <code>main.main</code> is a niladic function with no return type. Notice that <code>main.main</code> is a niladic function with no return type.
It's defined that way. Falling off the end of <code>main.main</code> means It's defined that way. Falling off the end of <code>main.main</code> means
...@@ -234,7 +266,7 @@ about pointers to arrays. ...@@ -234,7 +266,7 @@ about pointers to arrays.
The size of the array is part of its type; however, one can declare The size of the array is part of its type; however, one can declare
a <i>slice</i> variable, to which one can assign a pointer to a <i>slice</i> variable, to which one can assign a pointer to
any array any array
with the same element type or - much more commonly - a <i>slice with the same element type or&mdash;much more commonly&mdash;a <i>slice
expression</i> of the form <code>a[low : high]</code>, representing expression</i> of the form <code>a[low : high]</code>, representing
the subarray indexed by <code>low</code> through <code>high-1</code>. the subarray indexed by <code>low</code> through <code>high-1</code>.
Slices look a lot like arrays but have Slices look a lot like arrays but have
...@@ -276,7 +308,7 @@ and invoke it like this: ...@@ -276,7 +308,7 @@ and invoke it like this:
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.
The expression <code>[3]int{1,2,3}</code> -- a type followed by a brace-bounded expression The expression <code>[3]int{1,2,3}</code> -- a type followed by a brace-bounded expression
-- is a constructor for a value, in this case an array of 3 <code>ints</code>. Putting an <code>&</code> -- is a constructor for a value, in this case an array of 3 <code>ints</code>. Putting an <code>&amp;</code>
in front gives us the address of a unique instance of the value. We pass the in front gives us the address of a unique instance of the value. We pass the
pointer to <code>sum()</code> by (automatically) promoting it to a slice. pointer to <code>sum()</code> by (automatically) promoting it to a slice.
<p> <p>
...@@ -288,7 +320,7 @@ elements for you, use <code>...</code> as the array size: ...@@ -288,7 +320,7 @@ elements for you, use <code>...</code> as the array size:
</pre> </pre>
<p> <p>
In practice, though, unless you're meticulous about storage layout within a In practice, though, unless you're meticulous about storage layout within a
data structure, a slice itself - using empty brackets and no <code>&</code> - is all you need: data structure, a slice itself - using empty brackets and no <code>&amp;</code> - is all you need:
<p> <p>
<pre> <pre>
s := sum([]int{1,2,3}); s := sum([]int{1,2,3});
...@@ -297,7 +329,7 @@ data structure, a slice itself - using empty brackets and no <code>&</code> - is ...@@ -297,7 +329,7 @@ data structure, a slice itself - using empty brackets and no <code>&</code> - is
There are also maps, which you can initialize like this: There are also maps, which you can initialize like this:
<p> <p>
<pre> <pre>
m := map[string] int {"one":1 , "two":2} m := map[string]int{"one":1 , "two":2}
</pre> </pre>
<p> <p>
The built-in function <code>len()</code>, which returns number of elements, The built-in function <code>len()</code>, which returns number of elements,
...@@ -330,14 +362,14 @@ referencing the same underlying data will see the modification. For these three ...@@ -330,14 +362,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>: types you want to use the built-in function <code>make()</code>:
<p> <p>
<pre> <pre>
m := make(map[string] int); m := make(map[string]int);
</pre> </pre>
<p> <p>
This statement initializes a new map ready to store entries. This statement initializes a new map ready to store entries.
If you just declare the map, as in If you just declare the map, as in
<p> <p>
<pre> <pre>
var m map[string] int; var m map[string]int;
</pre> </pre>
<p> <p>
it creates a <code>nil</code> reference that cannot hold anything. To use the map, it creates a <code>nil</code> reference that cannot hold anything. To use the map,
...@@ -352,7 +384,7 @@ declaring an uninitialized variable and taking its address. ...@@ -352,7 +384,7 @@ declaring an uninitialized variable and taking its address.
<h2>An Interlude about Constants</h2> <h2>An Interlude about Constants</h2>
<p> <p>
Although integers come in lots of sizes in Go, integer constants do not. Although integers come in lots of sizes in Go, integer constants do not.
There are no constants like <code>0ll</code> or <code>0x0UL</code>. Instead, integer There are no constants like <code>0LL</code> or <code>0x0UL</code>. Instead, integer
constants are evaluated as large-precision values that constants are evaluated as large-precision values that
can overflow only when they are assigned to an integer variable with can overflow only when they are assigned to an integer variable with
too little precision to represent the value. too little precision to represent the value.
...@@ -394,7 +426,7 @@ sort of open/close/read/write interface. Here's the start of <code>file.go</cod ...@@ -394,7 +426,7 @@ sort of open/close/read/write interface. Here's the start of <code>file.go</cod
10 ) 10 )
<p> <p>
12 type File struct { 12 type File struct {
13 fd int; // file descriptor number 13 fd int; // file descriptor number
14 name string; // file name at Open time 14 name string; // file name at Open time
15 } 15 }
</pre> </pre>
...@@ -415,8 +447,8 @@ that the file descriptor refers to. ...@@ -415,8 +447,8 @@ that the file descriptor refers to.
<p> <p>
Because <code>File</code> starts with a capital letter, the type is available outside the package, Because <code>File</code> starts with a capital letter, the type is available outside the package,
that is, by users of the package. In Go the rule about visibility of information is that is, by users of the package. In Go the rule about visibility of information is
simple: if a name (of a top-level type, function, method, constant, variable, or of simple: if a name (of a top-level type, function, method, constant or variable, or of
a structure field) is capitalized, users of the package may see it. Otherwise, the a structure field or method) is capitalized, users of the package may see it. Otherwise, the
name and hence the thing being named is visible only inside the package in which name and hence the thing being named is visible only inside the package in which
it is declared. This is more than a convention; the rule is enforced by the compiler. it is declared. This is more than a convention; the rule is enforced by the compiler.
In Go, the term for publicly visible names is ''exported''. In Go, the term for publicly visible names is ''exported''.
...@@ -545,7 +577,7 @@ the <code>struct</code> declaration itself. The <code>struct</code> declaration ...@@ -545,7 +577,7 @@ the <code>struct</code> declaration itself. The <code>struct</code> declaration
In fact, methods can be created for any type you name, such as an integer or In fact, methods can be created for any type you name, such as an integer or
array, not just for <code>structs</code>. We'll see an example with arrays later. array, not just for <code>structs</code>. We'll see an example with arrays later.
<p> <p>
The <code>String</code> method is so called because of printing convention we'll The <code>String</code> method is so called because of a printing convention we'll
describe later. describe later.
<p> <p>
The methods use the public variable <code>os.EINVAL</code> to return the (<code>os.Error</code> The methods use the public variable <code>os.EINVAL</code> to return the (<code>os.Error</code>
...@@ -607,13 +639,13 @@ Building on the <code>file</code> package, here's a simple version of the Unix u ...@@ -607,13 +639,13 @@ Building on the <code>file</code> package, here's a simple version of the Unix u
17 for { 17 for {
18 switch nr, er := f.Read(&amp;buf); true { 18 switch nr, er := f.Read(&amp;buf); true {
19 case nr &lt; 0: 19 case nr &lt; 0:
20 fmt.Fprintf(os.Stderr, &quot;error reading from %s: %s\n&quot;, f.String(), er.String()); 20 fmt.Fprintf(os.Stderr, &quot;cat: error reading from %s: %s\n&quot;, f.String(), er.String());
21 os.Exit(1); 21 os.Exit(1);
22 case nr == 0: // EOF 22 case nr == 0: // EOF
23 return; 23 return;
24 case nr &gt; 0: 24 case nr &gt; 0:
25 if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr { 25 if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
26 fmt.Fprintf(os.Stderr, &quot;error writing from %s: %s\n&quot;, f.String(), ew.String()); 26 fmt.Fprintf(os.Stderr, &quot;cat: error writing from %s: %s\n&quot;, f.String(), ew.String());
27 } 27 }
28 } 28 }
29 } 29 }
...@@ -627,7 +659,7 @@ Building on the <code>file</code> package, here's a simple version of the Unix u ...@@ -627,7 +659,7 @@ Building on the <code>file</code> package, here's a simple version of the Unix u
37 for i := 0; i &lt; flag.NArg(); i++ { 37 for i := 0; i &lt; flag.NArg(); i++ {
38 f, err := file.Open(flag.Arg(i), 0, 0); 38 f, err := file.Open(flag.Arg(i), 0, 0);
39 if f == nil { 39 if f == nil {
40 fmt.Fprintf(os.Stderr, &quot;can't open %s: error %s\n&quot;, flag.Arg(i), err); 40 fmt.Fprintf(os.Stderr, &quot;cat: can't open %s: error %s\n&quot;, flag.Arg(i), err);
41 os.Exit(1); 41 os.Exit(1);
42 } 42 }
43 cat(f); 43 cat(f);
...@@ -702,7 +734,7 @@ we have a second implementation of the <code>reader</code> interface. ...@@ -702,7 +734,7 @@ we have a second implementation of the <code>reader</code> interface.
50 // end of rotate13 implementation 50 // end of rotate13 implementation
</pre> </pre>
<p> <p>
(The <code>rot13</code> function called on line 42 is trivial and not worth reproducing.) (The <code>rot13</code> function called on line 42 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>
...@@ -723,14 +755,14 @@ and use it from within a mostly unchanged <code>cat()</code> function: ...@@ -723,14 +755,14 @@ and use it from within a mostly unchanged <code>cat()</code> function:
59 for { 59 for {
60 switch nr, er := r.Read(&amp;buf); { 60 switch nr, er := r.Read(&amp;buf); {
61 case nr &lt; 0: 61 case nr &lt; 0:
62 fmt.Fprintf(os.Stderr, &quot;error reading from %s: %s\n&quot;, r.String(), er.String()); 62 fmt.Fprintf(os.Stderr, &quot;cat: error reading from %s: %s\n&quot;, r.String(), er.String());
63 os.Exit(1); 63 os.Exit(1);
64 case nr == 0: // EOF 64 case nr == 0: // EOF
65 return; 65 return;
66 case nr &gt; 0: 66 case nr &gt; 0:
67 nw, ew := file.Stdout.Write(buf[0:nr]); 67 nw, ew := file.Stdout.Write(buf[0:nr]);
68 if nw != nr { 68 if nw != nr {
69 fmt.Fprintf(os.Stderr, &quot;error writing from %s: %s\n&quot;, r.String(), ew.String()); 69 fmt.Fprintf(os.Stderr, &quot;cat: error writing from %s: %s\n&quot;, r.String(), ew.String());
70 } 70 }
71 } 71 }
72 } 72 }
...@@ -739,7 +771,7 @@ and use it from within a mostly unchanged <code>cat()</code> function: ...@@ -739,7 +771,7 @@ and use it from within a mostly unchanged <code>cat()</code> function:
<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.)
Lines 56 through 59 set it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code> Lines 56 through 58 set 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 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>, 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>. even though under the covers it holds a pointer to a <code>struct</code>.
...@@ -838,8 +870,8 @@ to implement the three methods for that type, like this: ...@@ -838,8 +870,8 @@ to implement the three methods for that type, like this:
<pre> <!-- progs/sortmain.go /type.day/ /Swap/ --> <pre> <!-- progs/sortmain.go /type.day/ /Swap/ -->
30 type day struct { 30 type day struct {
31 num int; 31 num int;
32 short_name string; 32 shortName string;
33 long_name string; 33 longName string;
34 } 34 }
<p> <p>
36 type dayArray struct { 36 type dayArray struct {
...@@ -972,7 +1004,7 @@ Schematically, given a value <code>v</code>, it does this: ...@@ -972,7 +1004,7 @@ Schematically, given a value <code>v</code>, it does this:
if ok { if ok {
result = s.String() result = s.String()
} else { } else {
result = default_output(v) result = defaultOutput(v)
} }
</pre> </pre>
<p> <p>
...@@ -1002,7 +1034,7 @@ interface type defined in the <code>io</code> library: ...@@ -1002,7 +1034,7 @@ interface type defined in the <code>io</code> library:
(This interface is another conventional name, this time for <code>Write</code>; there are also (This interface is another conventional name, this time for <code>Write</code>; there are also
<code>io.Reader</code>, <code>io.ReadWriter</code>, and so on.) <code>io.Reader</code>, <code>io.ReadWriter</code>, and so on.)
Thus you can call <code>Fprintf</code> on any type that implements a standard <code>Write()</code> Thus you can call <code>Fprintf</code> on any type that implements a standard <code>Write()</code>
method, not just files but also network channels, buffers, rot13ers, whatever method, not just files but also network channels, buffers, whatever
you want. you want.
<p> <p>
<h2>Prime numbers</h2> <h2>Prime numbers</h2>
...@@ -1010,7 +1042,10 @@ you want. ...@@ -1010,7 +1042,10 @@ you want.
Now we come to processes and communication -- concurrent programming. Now we come to processes and communication -- concurrent programming.
It's a big subject so to be brief we assume some familiarity with the topic. It's a big subject so to be brief we assume some familiarity with the topic.
<p> <p>
A classic program in the style is the prime sieve of Eratosthenes. A classic program in the style is a prime sieve.
(The sieve of Eratosthenes is computationationally more efficient than
the algorithm presented here, but we are more interested in concurrency than
algorithmics at the moment.)
It works by taking a stream of all the natural numbers and introducing It works by taking a stream of all the natural numbers and introducing
a sequence of filters, one for each prime, to winnow the multiples of a sequence of filters, one for each prime, to winnow the multiples of
that prime. At each step we have a sequence of filters of the primes that prime. At each step we have a sequence of filters of the primes
...@@ -1310,6 +1345,3 @@ at the end of main: ...@@ -1310,6 +1345,3 @@ at the end of main:
<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.
</table>
</body>
</html>
...@@ -2,12 +2,15 @@ ...@@ -2,12 +2,15 @@
Introduction Introduction
---- ----
This document is a tutorial introduction to the basics of the Go systems programming This document is a tutorial introduction to the basics of the Go programming
language, intended for programmers familiar with C or C++. It is not a comprehensive language, intended for programmers familiar with C or C++. It is not a comprehensive
guide to the language; at the moment the document closest to that is the guide to the language; at the moment the document closest to that is the
<a href='/doc/go_spec.html'>language specification.</a> <a href='/doc/go_spec.html'>language specification</a>.
After you've read this tutorial, you might want to look at
<a href='/doc/effective_go.html'>Effective Go</a>,
which digs deeper into how the language is used.
The presentation proceeds through a series of modest programs to illustrate The presentation here proceeds through a series of modest programs to illustrate
key features of the language. All the programs work (at time of writing) and are key features of the language. All the programs work (at time of writing) and are
checked into the repository in the directory <a href='/doc/progs'>"/doc/progs/"</a>. checked into the repository in the directory <a href='/doc/progs'>"/doc/progs/"</a>.
...@@ -40,6 +43,32 @@ The comment convention is the same as in C++: ...@@ -40,6 +43,32 @@ The comment convention is the same as in C++:
Later we'll have much more to say about printing. Later we'll have much more to say about printing.
Compiling
----
Go is a compiled language. At the moment there are two compilers.
"Gccgo" is a Go compiler that uses the GCC back end. There is also a
suite of compilers with different (and odd) names for each architecture:
"6g" for the 64-bit x86, "8g" for the 32-bit x86, and more. These
compilers run significantly faster but generate less efficient code
than "gccgo". At the time of writing (late 2009), they also have
a more robust run-time system although "gccgo" is catching up.
Here's how to compile and run our program. With "6g", say,
$ 6g helloworld.go # compile; object goes into helloworld.6
$ 6l helloworld.6 # link; output goes into 6.out
$ 6.out
Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
$
With "gccgo" it looks a little more traditional.
$ gccgo helloworld.go
$ a.out
Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
$
Echo Echo
---- ----
...@@ -48,10 +77,10 @@ Next up, here's a version of the Unix utility "echo(1)": ...@@ -48,10 +77,10 @@ Next up, here's a version of the Unix utility "echo(1)":
--PROG progs/echo.go /package/ END --PROG progs/echo.go /package/ END
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 "func" introducing a function. The keywords "var", "const", and "type" we saw "func" introduce a function. The keywords "var", "const", and "type"
(not used yet) also introduce declarations, as does "import". (not used yet) also introduce declarations, as does "import".
Notice that we can group declarations of the same sort into Notice that we can group declarations of the same sort into
parenthesized, semicolon-separated lists if we want, as on lines 4-10 and 14-17. parenthesized, semicolon-separated lists if we want, as on lines 7-10 and 14-17.
But it's not necessary to do so; we could have said But it's not necessary to do so; we could have said
const Space = " " const Space = " "
...@@ -122,7 +151,7 @@ Later examples will show some other ways "for" can be written. ...@@ -122,7 +151,7 @@ Later examples will show some other ways "for" can be written.
The body of the loop builds up the string "s" by appending (using "+=") The body of the loop builds up the string "s" by appending (using "+=")
the flags and separating spaces. After the loop, if the "-n" flag is not the flags and separating spaces. After the loop, if the "-n" flag is not
set, it appends a newline, and then writes the result. set, the program appends a newline. Finally, it writes the result.
Notice that "main.main" is a niladic function with no return type. Notice that "main.main" is a niladic function with no return type.
It's defined that way. Falling off the end of "main.main" means It's defined that way. Falling off the end of "main.main" means
...@@ -177,7 +206,7 @@ about pointers to arrays. ...@@ -177,7 +206,7 @@ about pointers to arrays.
The size of the array is part of its type; however, one can declare The size of the array is part of its type; however, one can declare
a <i>slice</i> variable, to which one can assign a pointer to a <i>slice</i> variable, to which one can assign a pointer to
any array any array
with the same element type or - much more commonly - a <i>slice with the same element type or&mdash;much more commonly&mdash;a <i>slice
expression</i> of the form "a[low : high]", representing expression</i> of the form "a[low : high]", representing
the subarray indexed by "low" through "high-1". the subarray indexed by "low" through "high-1".
Slices look a lot like arrays but have Slices look a lot like arrays but have
...@@ -209,7 +238,7 @@ and invoke it like this: ...@@ -209,7 +238,7 @@ and invoke it like this:
Note how the return type ("int") is defined for "sum()" by stating it Note how the return type ("int") is defined for "sum()" by stating it
after the parameter list. after the parameter list.
The expression "[3]int{1,2,3}" -- a type followed by a brace-bounded expression The expression "[3]int{1,2,3}" -- a type followed by a brace-bounded expression
-- is a constructor for a value, in this case an array of 3 "ints". Putting an "&" -- is a constructor for a value, in this case an array of 3 "ints". Putting an "&amp;"
in front gives us the address of a unique instance of the value. We pass the in front gives us the address of a unique instance of the value. We pass the
pointer to "sum()" by (automatically) promoting it to a slice. pointer to "sum()" by (automatically) promoting it to a slice.
...@@ -219,13 +248,13 @@ elements for you, use "..." as the array size: ...@@ -219,13 +248,13 @@ elements for you, use "..." as the array size:
s := sum(&amp;[...]int{1,2,3}); s := sum(&amp;[...]int{1,2,3});
In practice, though, unless you're meticulous about storage layout within a In practice, though, unless you're meticulous about storage layout within a
data structure, a slice itself - using empty brackets and no "&" - is all you need: data structure, a slice itself - using empty brackets and no "&amp;" - is all you need:
s := sum([]int{1,2,3}); s := sum([]int{1,2,3});
There are also maps, which you can initialize like this: There are also maps, which you can initialize like this:
m := map[string] int {"one":1 , "two":2} m := map[string]int{"one":1 , "two":2}
The built-in function "len()", which returns number of elements, The built-in function "len()", which returns number of elements,
makes its first appearance in "sum". It works on strings, arrays, makes its first appearance in "sum". It works on strings, arrays,
...@@ -253,12 +282,12 @@ If you're holding a slice or a map and you modify its contents, other variables ...@@ -253,12 +282,12 @@ If you're holding a slice or a map and you modify its contents, other variables
referencing the same underlying data will see the modification. For these three referencing the same underlying data will see the modification. For these three
types you want to use the built-in function "make()": types you want to use the built-in function "make()":
m := make(map[string] int); m := make(map[string]int);
This statement initializes a new map ready to store entries. This statement initializes a new map ready to store entries.
If you just declare the map, as in If you just declare the map, as in
var m map[string] int; var m map[string]int;
it creates a "nil" reference that cannot hold anything. To use the map, it creates a "nil" reference that cannot hold anything. To use the map,
you must first initialize the reference using "make()" or by assignment to an you must first initialize the reference using "make()" or by assignment to an
...@@ -273,7 +302,7 @@ An Interlude about Constants ...@@ -273,7 +302,7 @@ An Interlude about Constants
---- ----
Although integers come in lots of sizes in Go, integer constants do not. Although integers come in lots of sizes in Go, integer constants do not.
There are no constants like "0ll" or "0x0UL". Instead, integer There are no constants like "0LL" or "0x0UL". Instead, integer
constants are evaluated as large-precision values that constants are evaluated as large-precision values that
can overflow only when they are assigned to an integer variable with can overflow only when they are assigned to an integer variable with
too little precision to represent the value. too little precision to represent the value.
...@@ -321,8 +350,8 @@ that the file descriptor refers to. ...@@ -321,8 +350,8 @@ that the file descriptor refers to.
Because "File" starts with a capital letter, the type is available outside the package, Because "File" starts with a capital letter, the type is available outside the package,
that is, by users of the package. In Go the rule about visibility of information is that is, by users of the package. In Go the rule about visibility of information is
simple: if a name (of a top-level type, function, method, constant, variable, or of simple: if a name (of a top-level type, function, method, constant or variable, or of
a structure field) is capitalized, users of the package may see it. Otherwise, the a structure field or method) is capitalized, users of the package may see it. Otherwise, the
name and hence the thing being named is visible only inside the package in which name and hence the thing being named is visible only inside the package in which
it is declared. This is more than a convention; the rule is enforced by the compiler. it is declared. This is more than a convention; the rule is enforced by the compiler.
In Go, the term for publicly visible names is ''exported''. In Go, the term for publicly visible names is ''exported''.
...@@ -390,7 +419,7 @@ the "struct" declaration itself. The "struct" declaration defines only data mem ...@@ -390,7 +419,7 @@ the "struct" declaration itself. The "struct" declaration defines only data mem
In fact, methods can be created for any type you name, such as an integer or In fact, methods can be created for any type you name, such as an integer or
array, not just for "structs". We'll see an example with arrays later. array, not just for "structs". We'll see an example with arrays later.
The "String" method is so called because of printing convention we'll The "String" method is so called because of a printing convention we'll
describe later. describe later.
The methods use the public variable "os.EINVAL" to return the ("os.Error" The methods use the public variable "os.EINVAL" to return the ("os.Error"
...@@ -459,7 +488,7 @@ we have a second implementation of the "reader" interface. ...@@ -459,7 +488,7 @@ we have a second implementation of the "reader" interface.
--PROG progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/ --PROG progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/
(The "rot13" function called on line 42 is trivial and not worth reproducing.) (The "rot13" function called on line 42 is trivial and not worth reproducing here.)
To use the new feature, we define a flag: To use the new feature, we define a flag:
...@@ -471,7 +500,7 @@ and use it from within a mostly unchanged "cat()" function: ...@@ -471,7 +500,7 @@ and use it from within a mostly unchanged "cat()" function:
(We could also do the wrapping in "main" and leave "cat()" mostly alone, except (We could also do the wrapping in "main" and leave "cat()" 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.)
Lines 56 through 59 set it all up: If the "rot13" flag is true, wrap the "reader" Lines 56 through 58 set it all up: If the "rot13" flag is true, wrap the "reader"
we received into a "rotate13" and proceed. Note that the interface variables we received into a "rotate13" and proceed. Note that the interface variables
are values, not pointers: the argument is of type "reader", not "*reader", are values, not pointers: the argument is of type "reader", not "*reader",
even though under the covers it holds a pointer to a "struct". even though under the covers it holds a pointer to a "struct".
...@@ -630,7 +659,7 @@ Schematically, given a value "v", it does this: ...@@ -630,7 +659,7 @@ Schematically, given a value "v", it does this:
if ok { if ok {
result = s.String() result = s.String()
} else { } else {
result = default_output(v) result = defaultOutput(v)
} }
The code uses a ``type assertion'' ("v.(Stringer)") to test if the value stored in The code uses a ``type assertion'' ("v.(Stringer)") to test if the value stored in
...@@ -657,7 +686,7 @@ interface type defined in the "io" library: ...@@ -657,7 +686,7 @@ interface type defined in the "io" library:
(This interface is another conventional name, this time for "Write"; there are also (This interface is another conventional name, this time for "Write"; there are also
"io.Reader", "io.ReadWriter", and so on.) "io.Reader", "io.ReadWriter", and so on.)
Thus you can call "Fprintf" on any type that implements a standard "Write()" Thus you can call "Fprintf" on any type that implements a standard "Write()"
method, not just files but also network channels, buffers, rot13ers, whatever method, not just files but also network channels, buffers, whatever
you want. you want.
Prime numbers Prime numbers
...@@ -666,7 +695,10 @@ Prime numbers ...@@ -666,7 +695,10 @@ Prime numbers
Now we come to processes and communication -- concurrent programming. Now we come to processes and communication -- concurrent programming.
It's a big subject so to be brief we assume some familiarity with the topic. It's a big subject so to be brief we assume some familiarity with the topic.
A classic program in the style is the prime sieve of Eratosthenes. A classic program in the style is a prime sieve.
(The sieve of Eratosthenes is computationationally more efficient than
the algorithm presented here, but we are more interested in concurrency than
algorithmics at the moment.)
It works by taking a stream of all the natural numbers and introducing It works by taking a stream of all the natural numbers and introducing
a sequence of filters, one for each prime, to winnow the multiples of a sequence of filters, one for each prime, to winnow the multiples of
that prime. At each step we have a sequence of filters of the primes that prime. At each step we have a sequence of filters of the primes
...@@ -825,6 +857,3 @@ at the end of main: ...@@ -825,6 +857,3 @@ at the end of main:
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.
</table>
</body>
</html>
...@@ -17,13 +17,13 @@ func cat(f *file.File) { ...@@ -17,13 +17,13 @@ func cat(f *file.File) {
for { for {
switch nr, er := f.Read(&buf); true { switch nr, er := f.Read(&buf); true {
case nr < 0: case nr < 0:
fmt.Fprintf(os.Stderr, "error reading from %s: %s\n", f.String(), er.String()); fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String());
os.Exit(1); os.Exit(1);
case nr == 0: // EOF case nr == 0: // EOF
return; return;
case nr > 0: case nr > 0:
if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr { if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
fmt.Fprintf(os.Stderr, "error writing from %s: %s\n", f.String(), ew.String()); fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String());
} }
} }
} }
...@@ -37,7 +37,7 @@ func main() { ...@@ -37,7 +37,7 @@ func main() {
for i := 0; i < flag.NArg(); i++ { for i := 0; i < flag.NArg(); i++ {
f, err := file.Open(flag.Arg(i), 0, 0); f, err := file.Open(flag.Arg(i), 0, 0);
if f == nil { if f == nil {
fmt.Fprintf(os.Stderr, "can't open %s: error %s\n", flag.Arg(i), err); fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err);
os.Exit(1); os.Exit(1);
} }
cat(f); cat(f);
......
...@@ -59,14 +59,14 @@ func cat(r reader) { ...@@ -59,14 +59,14 @@ func cat(r reader) {
for { for {
switch nr, er := r.Read(&buf); { switch nr, er := r.Read(&buf); {
case nr < 0: case nr < 0:
fmt.Fprintf(os.Stderr, "error reading from %s: %s\n", r.String(), er.String()); fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String());
os.Exit(1); os.Exit(1);
case nr == 0: // EOF case nr == 0: // EOF
return; return;
case nr > 0: case nr > 0:
nw, ew := file.Stdout.Write(buf[0:nr]); nw, ew := file.Stdout.Write(buf[0:nr]);
if nw != nr { if nw != nr {
fmt.Fprintf(os.Stderr, "error writing from %s: %s\n", r.String(), ew.String()); fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String());
} }
} }
} }
...@@ -80,7 +80,7 @@ func main() { ...@@ -80,7 +80,7 @@ func main() {
for i := 0; i < flag.NArg(); i++ { for i := 0; i < flag.NArg(); i++ {
f, err := file.Open(flag.Arg(i), 0, 0); f, err := file.Open(flag.Arg(i), 0, 0);
if f == nil { if f == nil {
fmt.Fprintf(os.Stderr, "can't open %s: error %s\n", flag.Arg(i), err); fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err);
os.Exit(1); os.Exit(1);
} }
cat(f); cat(f);
......
...@@ -12,8 +12,8 @@ import ( ...@@ -12,8 +12,8 @@ import (
var n_flag = flag.Bool("n", false, "don't print final newline") var n_flag = flag.Bool("n", false, "don't print final newline")
const ( const (
kSpace = " "; Space = " ";
kNewline = "\n"; Newline = "\n";
) )
func main() { func main() {
...@@ -21,12 +21,12 @@ func main() { ...@@ -21,12 +21,12 @@ func main() {
var s string = ""; var s string = "";
for i := 0; i < flag.NArg(); i++ { for i := 0; i < flag.NArg(); i++ {
if i > 0 { if i > 0 {
s += kSpace s += Space
} }
s += flag.Arg(i) s += flag.Arg(i)
} }
if !*n_flag { if !*n_flag {
s += kNewline s += Newline
} }
os.Stdout.WriteString(s); os.Stdout.WriteString(s);
} }
...@@ -10,7 +10,7 @@ import ( ...@@ -10,7 +10,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
} }
......
...@@ -29,8 +29,8 @@ func strings() { ...@@ -29,8 +29,8 @@ func strings() {
type day struct { type day struct {
num int; num int;
short_name string; shortName string;
long_name string; longName string;
} }
type dayArray struct { type dayArray struct {
...@@ -56,7 +56,7 @@ func days() { ...@@ -56,7 +56,7 @@ func days() {
panic() panic()
} }
for _, d := range data { for _, d := range data {
fmt.Printf("%s ", d.long_name) fmt.Printf("%s ", d.longName)
} }
fmt.Printf("\n") fmt.Printf("\n")
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment