From 7201b0c27c45d06ccb1f2ac4f275200a863bae91 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 28 Feb 2012 13:35:58 +1100 Subject: [PATCH] tutorial: delete Instead we'll point people at the Tour and beef up code.html. Fixes #3107. R=golang-dev, bradfitz, r, adg CC=golang-dev https://golang.org/cl/5697077 --- doc/Makefile | 1 - doc/docs.html | 13 +- doc/effective_go.html | 8 +- doc/effective_go.tmpl | 8 +- doc/go_for_cpp_programmers.html | 5 +- doc/go_tutorial.html | 1452 ------------------------------- doc/go_tutorial.tmpl | 1040 ---------------------- doc/install-source.html | 3 +- doc/makehtml | 2 +- doc/progs/cat.go | 47 - doc/progs/cat_rot13.go | 91 -- doc/progs/echo.go | 32 - doc/progs/file.go | 77 -- doc/progs/file_windows.go | 77 -- doc/progs/run | 58 -- doc/progs/sieve.go | 38 - doc/progs/sieve1.go | 51 -- doc/progs/sortmain.go | 68 -- doc/talks/go_talk-20100323.html | 2 +- src/cmd/godoc/main.go | 2 +- 20 files changed, 20 insertions(+), 3055 deletions(-) delete mode 100644 doc/go_tutorial.html delete mode 100644 doc/go_tutorial.tmpl delete mode 100644 doc/progs/cat.go delete mode 100644 doc/progs/cat_rot13.go delete mode 100644 doc/progs/echo.go delete mode 100644 doc/progs/file.go delete mode 100644 doc/progs/file_windows.go delete mode 100644 doc/progs/sieve.go delete mode 100644 doc/progs/sieve1.go delete mode 100644 doc/progs/sortmain.go diff --git a/doc/Makefile b/doc/Makefile index e834316b9c..40e8569b23 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -8,7 +8,6 @@ HTML=\ articles/slices_usage_and_internals.html\ effective_go.html\ go1.html\ - go_tutorial.html\ all: tmpltohtml $(HTML) diff --git a/doc/docs.html b/doc/docs.html index 5dacee6634..171c5cabf5 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -32,17 +32,10 @@ learned. You can take the tour online or install it locally.

-

A Tutorial for the Go Programming Language

-

-The first tutorial. An introductory text that touches upon several core -concepts: syntax, types, allocation, constants, I/O, sorting, printing, -goroutines, and channels. -

-

Effective Go

A document that gives tips for writing clear, idiomatic Go code. -A must read for any new Go programmer. It augments the tutorial and +A must read for any new Go programmer. It augments the tour and the language specification, both of which should be read first.

@@ -226,7 +219,7 @@ Go libraries.

Czech — ČeÅ¡tina

@@ -245,7 +238,7 @@ Go libraries.

German — Deutsch

diff --git a/doc/effective_go.html b/doc/effective_go.html index e3e19bd392..c9eac99ba5 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -31,8 +31,10 @@ will be easy for other Go programmers to understand.

This document gives tips for writing clear, idiomatic Go code. -It augments the language specification -and the tutorial, both of which you +It augments the language specification, +the Tour of Go, +and How to Write Go Code, +all of which you should read first.

@@ -1454,7 +1456,7 @@ fmt.Println(fmt.Sprint("Hello ", 23))

As mentioned in -the tutorial, fmt.Fprint +the Tour, fmt.Fprint and friends take as a first argument any object that implements the io.Writer interface; the variables os.Stdout and os.Stderr are familiar instances. diff --git a/doc/effective_go.tmpl b/doc/effective_go.tmpl index 5763cacdab..446b0525e3 100644 --- a/doc/effective_go.tmpl +++ b/doc/effective_go.tmpl @@ -27,8 +27,10 @@ will be easy for other Go programmers to understand.

This document gives tips for writing clear, idiomatic Go code. -It augments the language specification -and the tutorial, both of which you +It augments the language specification, +the Tour of Go, +and How to Write Go Code, +all of which you should read first.

@@ -1450,7 +1452,7 @@ fmt.Println(fmt.Sprint("Hello ", 23))

As mentioned in -the tutorial, fmt.Fprint +the Tour, fmt.Fprint and friends take as a first argument any object that implements the io.Writer interface; the variables os.Stdout and os.Stderr are familiar instances. diff --git a/doc/go_for_cpp_programmers.html b/doc/go_for_cpp_programmers.html index 8e215190fa..7a9f616079 100644 --- a/doc/go_for_cpp_programmers.html +++ b/doc/go_for_cpp_programmers.html @@ -11,8 +11,9 @@ to nothing about the similarities.

For a more general introduction to Go, see the -Go tutorial and -Effective Go. +Go Tour, +How to Write Go Code +and Effective Go.

For a detailed description of the Go language, see the diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html deleted file mode 100644 index 589262363f..0000000000 --- a/doc/go_tutorial.html +++ /dev/null @@ -1,1452 +0,0 @@ - - - - -

Introduction

-

-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 -guide to the language; at the moment the document closest to that is the -language specification. -After you've read this tutorial, you should look at -Effective Go, -which digs deeper into how the language is used and -talks about the style and idioms of programming in Go. -An interactive introduction to Go is available, called -A Tour of Go. -

-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 -checked into the repository in the directory /doc/progs/. -

-

Hello, World

-

-Let's start in the usual way: -

-

package main
-
-import fmt "fmt" // Package implementing formatted I/O.
-
-func main() {
-    fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
-}
-

-Every Go source file declares, using a package statement, which package it's part of. -It may also import other packages to use their facilities. -This program imports the package fmt to gain access to -our old, now capitalized and package-qualified, friend, fmt.Printf. -

-Functions are introduced with the func keyword. -The main package's main function is where the program starts running (after -any initialization). -

-String constants can contain Unicode characters, encoded in UTF-8. -(In fact, Go source files are defined to be encoded in UTF-8.) -

-The comment convention is the same as in C++: -

-

-/* ... */
-// ...
-
-

-Later we'll have much more to say about printing. -

-

Semicolons

-

-You might have noticed that our program has no semicolons. In Go -code, the only place you typically see semicolons is separating the -clauses of for loops and the like; they are not necessary after -every statement. -

-In fact, what happens is that the formal language uses semicolons, -much as in C or Java, but they are inserted automatically -at the end of every line that looks like the end of a statement. You -don't need to type them yourself. -

-For details about how this is done you can see the language -specification, but in practice all you need to know is that you -never need to put a semicolon at the end of a line. (You can put -them in if you want to write multiple statements per line.) As an -extra help, you can also leave out a semicolon immediately before -a closing brace. -

-This approach makes for clean-looking, semicolon-free code. The -one surprise is that it's important to put the opening -brace of a construct such as an if statement on the same line as -the if; if you don't, there are situations that may not compile -or may give the wrong result. The language forces the brace style -to some extent. -

-

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

-

-Next up, here's a version of the Unix utility echo(1): -

-

package main
-
-import (
-    "flag" // command line option parser
-    "os"
-)
-
-var omitNewline = flag.Bool("n", false, "don't print final newline")
-
-const (
-    Space   = " "
-    Newline = "\n"
-)
-
-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)
-}
-

-This program is small but it's doing a number of new things. In the last example, -we saw func introduce a function. The keywords var, const, and type -(not used yet) also introduce declarations, as does import. -Notice that we can group declarations of the same sort into -parenthesized lists, one item per line, as in the import and const clauses here. -But it's not necessary to do so; we could have said -

-

-const Space = " "
-const Newline = "\n"
-
-

-This program imports the "os" package to access its Stdout variable, of type -*os.File. The import statement is actually a declaration: in its general form, -as used in our ``hello world'' program, -it names the identifier (fmt) -that will be used to access members of the package imported from the file ("fmt"), -found in the current directory or in a standard location. -In this program, though, we've dropped the explicit name from the imports; by default, -packages are imported using the name defined by the imported package, -which by convention is of course the file name itself. Our ``hello world'' program -could have said just import "fmt". -

-You can specify your -own import names if you want but it's only necessary if you need to resolve -a naming conflict. -

-Given os.Stdout we can use its WriteString method to print the string. -

-After importing the flag package, we use a var declaration -to create and initialize a global variable, called omitNewline, -to hold the value of echo's -n flag. -The variable has type *bool, pointer to bool. -

-In main.main, we parse the arguments (the call to flag.Parse) and then create a local -string variable with which to build the output. -

-The declaration statement has the form -

-

-var s string = ""
-
-

-This is the var keyword, followed by the name of the variable, followed by -its type, followed by an equals sign and an initial value for the variable. -

-Go tries to be terse, and this declaration could be shortened. Since the -string constant is of type string, we don't have to tell the compiler that. -We could write -

-

-var s = ""
-
-

-or we could go even shorter and write the idiom -

-

-s := ""
-
-

-The := operator is used a lot in Go to represent an initializing declaration. -There's one in the for clause on the next line: -

-

    for i := 0; i < flag.NArg(); i++ {
-

-The flag package has parsed the arguments and left the non-flag arguments -in a list that can be iterated over in the obvious way. -

-The Go for statement differs from that of C in a number of ways. First, -it's the only looping construct; there is no while or do. Second, -there are no parentheses on the clause, but the braces on the body -are mandatory. The same applies to the if and switch statements. -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 arguments and separating spaces. After the loop, if the -n flag is not -set, the program appends a newline. Finally, it writes the result. -

-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 -''success''; if you want to signal an erroneous return, call -

-

-os.Exit(1)
-
-

-The os package contains other essentials for getting -started; for instance, os.Args is a slice used by the -flag package to access the command-line arguments. -

-

An Interlude about Types

-

-Go has some familiar types such as int and uint (unsigned int), which represent -values of the ''appropriate'' size for the machine. It also defines -explicitly-sized types such as int8, float64, and so on, plus -unsigned integer types such as uint, uint32, etc. -These are distinct types; even if int and int32 are both 32 bits in size, -they are not the same type. There is also a byte synonym for -uint8, which is the element type for strings. -

-Floating-point types are always sized: float32 and float64, -plus complex64 (two float32s) and complex128 -(two float64s). Complex numbers are outside the -scope of this tutorial. -

-Speaking of string, that's a built-in type as well. Strings are -immutable values—they are not just arrays of byte values. -Once you've built a string value, you can't change it, although -of course you can change a string variable simply by -reassigning it. This snippet from strings.go is legal code: -

-

    s := "hello"
-    if s[1] != 'e' {
-        os.Exit(1)
-    }
-    s = "good bye"
-    var p *string = &s
-    *p = "ciao"
-

-However the following statements are illegal because they would modify -a string value: -

-

-s[0] = 'x'
-(*p)[1] = 'y'
-
-

-In C++ terms, Go strings are a bit like const strings, while pointers -to strings are analogous to const string references. -

-Yes, there are pointers. However, Go simplifies their use a little; -read on. -

-Arrays are declared like this: -

-

-var arrayOfInt [10]int
-
-

-Arrays, like strings, are values, but they are mutable. This differs -from C, in which arrayOfInt would be usable as a pointer to int. -In Go, since arrays are values, it's meaningful (and useful) to talk -about pointers to arrays. -

-The size of the array is part of its type; however, one can declare -a slice variable to hold a reference to any array, of any size, -with the same element type. -A slice -expression has the form a[low : high], representing -the internal array indexed from low through high-1; the resulting -slice is indexed from 0 through high-low-1. -In short, slices look a lot like arrays but with -no explicit size ([] vs. [10]) and they reference a segment of -an underlying, usually anonymous, regular array. Multiple slices -can share data if they represent pieces of the same array; -multiple arrays can never share data. -

-Slices are much more common in Go programs than -regular arrays; they're more flexible, have reference semantics, -and are efficient. What they lack is the precise control of storage -layout of a regular array; if you want to have a hundred elements -of an array stored within your structure, you should use a regular -array. To create one, use a compound value constructor—an -expression formed -from a type followed by a brace-bounded expression like this: -

-

-[3]int{1,2,3}
-
-

-In this case the constructor builds an array of 3 ints. -

-When passing an array to a function, you almost always want -to declare the formal parameter to be a slice. When you call -the function, slice the array to create -(efficiently) a slice reference and pass that. -By default, the lower and upper bounds of a slice match the -ends of the existing object, so the concise notation [:] -will slice the whole array. -

-Using slices one can write this function (from sum.go): -

-

func sum(a []int) int { // returns an int
-    s := 0
-    for i := 0; i < len(a); i++ {
-        s += a[i]
-    }
-    return s
-}
-

-Note how the return type (int) is defined for sum by stating it -after the parameter list. -

-To call the function, we slice the array. This code (we'll show -a simpler way in a moment) constructs -an array and slices it: -

-

-x := [3]int{1,2,3}
-s := sum(x[:])
-
-

-If you are creating a regular array but want the compiler to count the -elements for you, use ... as the array size: -

-

-x := [...]int{1,2,3}
-s := sum(x[:])
-
-

-That's fussier than necessary, though. -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: -

-

-s := sum([]int{1,2,3})
-
-

-There are also maps, which you can initialize like this: -

-

-m := map[string]int{"one":1 , "two":2}
-
-

-The built-in function len, which returns number of elements, -makes its first appearance in sum. It works on strings, arrays, -slices, maps, and channels. -

-By the way, another thing that works on strings, arrays, slices, maps -and channels is the range clause on for loops. Instead of writing -

-

-for i := 0; i < len(a); i++ { ... }
-
-

-to loop over the elements of a slice (or map or ...) , we could write -

-

-for i, v := range a { ... }
-
-

-This assigns i to the index and v to the value of the successive -elements of the target of the range. See -Effective Go -for more examples of its use. -

-

-

An Interlude about Allocation

-

-Most types in Go are values. If you have an int or a struct -or an array, assignment -copies the contents of the object. -To allocate a new variable, use the built-in function new, which -returns a pointer to the allocated storage. -

-

-type T struct { a, b int }
-var t *T = new(T)
-
-

-or the more idiomatic -

-

-t := new(T)
-
-

-Some types—maps, slices, and channels (see below)—have reference semantics. -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 -types you want to use the built-in function make: -

-

-m := make(map[string]int)
-
-

-This statement initializes a new map ready to store entries. -If you just declare the map, as in -

-

-var m map[string]int
-
-

-it creates a nil reference that cannot hold anything. To use the map, -you must first initialize the reference using make or by assignment from an -existing map. -

-Note that new(T) returns type *T while make(T) returns type -T. If you (mistakenly) allocate a reference object with new rather than make, -you receive a pointer to a nil reference, equivalent to -declaring an uninitialized variable and taking its address. -

-

An Interlude about Constants

-

-Although integers come in lots of sizes in Go, integer constants do not. -There are no constants like 0LL or 0x0UL. Instead, integer -constants are evaluated as large-precision values that -can overflow only when they are assigned to an integer variable with -too little precision to represent the value. -

-

-const hardEight = (1 << 100) >> 97  // legal
-
-

-There are nuances that deserve redirection to the legalese of the -language specification but here are some illustrative examples: -

-

-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
-
-

-Conversions only work for simple cases such as converting ints of one -sign or size to another and between integers and floating-point numbers, -plus a couple of other instances outside the scope of a tutorial. -There are no automatic numeric conversions of any kind in Go, -other than that of making constants have concrete size and type when -assigned to a variable. -

-

An I/O Package

-

-Next we'll look at a simple package for doing Unix file I/O with an -open/close/read/write interface. -Here's the start of file.go: -

-

package file
-
-import (
-    "os"
-    "syscall"
-)
-
-type File struct {
-    fd   int    // file descriptor number
-    name string // file name at Open time
-}
-

-The first few lines declare the name of the -package—file—and then import two packages. The os -package hides the differences -between various operating systems to give a consistent view of files and -so on; here we're going to use its error handling utilities -and reproduce the rudiments of its file I/O. -

-The other item is the low-level, external syscall package, which provides -a primitive interface to the underlying operating system's calls. -The syscall package is very system-dependent, and the way it's -used here works only on Unix-like systems, -but the general ideas explored here apply broadly. -(A Windows version is available in -file_windows.go.) -

-Next is a type definition: the type keyword introduces a type declaration, -in this case a data structure called File. -To make things a little more interesting, our File includes the name of the file -that the file descriptor refers to. -

-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 -simple: if a name (of a top-level type, function, method, constant or variable, or of -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 -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 the case of File, all its fields are lower case and so invisible to users, but we -will soon give it some exported, upper-case methods. -

-First, though, here is a factory to create a File: -

-

func newFile(fd int, name string) *File {
-    if fd < 0 {
-        return nil
-    }
-    return &File{fd, name}
-}
-

-This returns a pointer to a new File structure with the file descriptor and name -filled in. This code uses Go's notion of a ''composite literal'', analogous to -the ones used to build maps and arrays, to construct a new heap-allocated -object. We could write -

-

-n := new(File)
-n.fd = fd
-n.name = name
-return n
-
-

-but for simple structures like File it's easier to return the address of a -composite literal, as is done here in the return statement from newFile. -

-We can use the factory to construct some familiar, exported variables of type *File: -

-

var (
-    Stdin  = newFile(syscall.Stdin, "/dev/stdin")
-    Stdout = newFile(syscall.Stdout, "/dev/stdout")
-    Stderr = newFile(syscall.Stderr, "/dev/stderr")
-)
-

-The newFile function was not exported because it's internal. The proper, -exported factory to use is OpenFile (we'll explain that name in a moment): -

-

func OpenFile(name string, mode int, perm uint32) (file *File, err error) {
-    r, err := syscall.Open(name, mode, perm)
-    return newFile(r, name), err
-}
-

-There are a number of new things in these few lines. First, OpenFile returns -multiple values, a File and an error (more about errors in a moment). -We declare the -multi-value return as a parenthesized list of declarations; syntactically -they look just like a second parameter list. The function -syscall.Open -also has a multi-value return, which we can grab with the multi-variable -declaration on the first line; it declares r and e to hold the two values, -both of type int (although you'd have to look at the syscall package -to see that). Finally, OpenFile returns two values: a pointer to the new File -and the error. If syscall.Open fails, the file descriptor r will -be negative and newFile will return nil. -

-About those errors: The Go language includes a general notion of an error: -a pre-defined type error with properties (described below) -that make it a good basis for representing and handling errors. -It's a good idea to use its facility in your own interfaces, as we do here, for -consistent error handling throughout Go code. In Open we use a -conversion to translate Unix's integer errno value into the integer type -os.Errno, which is an implementation of error -

-Why OpenFile and not Open? To mimic Go's os package, which -our exercise is emulating. The os package takes the opportunity -to make the two commonest cases - open for read and create for -write - the simplest, just Open and Create. OpenFile is the -general case, analogous to the Unix system call Open. Here is -the implementation of our Open and Create; they're trivial -wrappers that eliminate common errors by capturing -the tricky standard arguments to open and, especially, to create a file: -

-

const (
-    O_RDONLY = syscall.O_RDONLY
-    O_RDWR   = syscall.O_RDWR
-    O_CREATE = syscall.O_CREAT
-    O_TRUNC  = syscall.O_TRUNC
-)
-
-func Open(name string) (file *File, err error) {
-    return OpenFile(name, O_RDONLY, 0)
-}
-

-

func Create(name string) (file *File, err error) {
-    return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
-}
-

-Back to our main story. -Now that we can build Files, we can write methods for them. To declare -a method of a type, we define a function to have an explicit receiver -of that type, placed -in parentheses before the function name. Here are some methods for *File, -each of which declares a receiver variable file. -

-

func (file *File) Close() error {
-    if file == nil {
-        return os.ErrInvalid
-    }
-    err := syscall.Close(file.fd)
-    file.fd = -1 // so it can't be closed again
-    return err
-}
-
-func (file *File) Read(b []byte) (ret int, err error) {
-    if file == nil {
-        return -1, os.ErrInvalid
-    }
-    r, err := syscall.Read(file.fd, b)
-    return int(r), err
-}
-
-func (file *File) Write(b []byte) (ret int, err error) {
-    if file == nil {
-        return -1, os.ErrInvalid
-    }
-    r, err := syscall.Write(file.fd, b)
-    return int(r), err
-}
-
-func (file *File) String() string {
-    return file.name
-}
-

-There is no implicit this and the receiver variable must be used to access -members of the structure. Methods are not declared within -the struct declaration itself. The struct declaration defines only data members. -In fact, methods can be created for almost any type you name, such as an integer or -array, not just for structs. We'll see an example with arrays later. -

-The String method is so called because of a printing convention we'll -describe later. -

-The methods use the public variable os.ErrInvalid to return the (error -version of the) Unix error code EINVAL. The os library defines a standard -set of such error values. -

-We can now use our new package: -

-

package main
-
-import (
-    "./file"
-    "fmt"
-    "os"
-)
-
-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.Error())
-        os.Exit(1)
-    }
-}
-

-The ''./'' in the import of ''./file'' tells the compiler -to use our own package rather than -something from the directory of installed packages. -(Also, ''file.go'' must be compiled before we can import the -package.) -

-Now we can compile and run the program. On Unix, this would be the result: -

-

-$ 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
-$
-
-

-

Rotting cats

-

-Building on the file package, here's a simple version of the Unix utility cat(1), -progs/cat.go: -

-

package main
-
-import (
-    "./file"
-    "flag"
-    "fmt"
-    "os"
-)
-
-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, er)
-            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, ew)
-                os.Exit(1)
-            }
-        }
-    }
-}
-
-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()
-    }
-}
-

-By now this should be easy to follow, but the switch statement introduces some -new features. Like a for loop, an if or switch can include an -initialization statement. The switch statement in cat uses one to create variables -nr and er to hold the return values from the call to f.Read. (The if a few lines later -has the same idea.) The switch 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 -they all have the same type. -

-Since the switch value is just true, we could leave it off—as is also -the situation -in a for statement, a missing value means true. In fact, such a switch -is a form of if-else chain. While we're here, it should be mentioned that in -switch statements each case has an implicit break. -

-The argument to file.Stdout.Write is created by slicing the array buf. -Slices provide the standard Go way to handle I/O buffers. -

-Now let's make a variant of cat that optionally does rot13 on its input. -It's easy to do by just processing the bytes, but instead we will exploit -Go's notion of an interface. -

-The cat subroutine uses only two methods of f: Read and String, -so let's start by defining an interface that has exactly those two methods. -Here is code from progs/cat_rot13.go: -

-

type reader interface {
-    Read(b []byte) (ret int, err error)
-    String() string
-}
-

-Any type that has the two methods of reader—regardless of whatever -other methods the type may also have—is said to implement the -interface. Since file.File implements these methods, it implements the -reader interface. We could tweak the cat subroutine to accept a reader -instead of a *file.File and it would work just fine, but let's embellish a little -first by writing a second type that implements reader, one that wraps an -existing reader and does rot13 on the data. To do this, we just define -the type and implement the methods and with no other bookkeeping, -we have a second implementation of the reader interface. -

-

type rotate13 struct {
-    source reader
-}
-
-func newRotate13(source reader) *rotate13 {
-    return &rotate13{source}
-}
-
-func (r13 *rotate13) Read(b []byte) (ret int, err error) {
-    r, e := r13.source.Read(b)
-    for i := 0; i < r; i++ {
-        b[i] = rot13(b[i])
-    }
-    return r, e
-}
-
-func (r13 *rotate13) String() string {
-    return r13.source.String()
-}
-

-(The rot13 function called in Read is trivial and not worth reproducing here.) -

-To use the new feature, we define a flag: -

-

var rot13Flag = flag.Bool("rot13", false, "rot13 the input")
-

-and use it from within a mostly unchanged cat function: -

-

func cat(r reader) {
-    const NBUF = 512
-    var buf [NBUF]byte
-
-    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, er)
-            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, ew)
-                os.Exit(1)
-            }
-        }
-    }
-}
-

-(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.) -The if at the top of cat sets it all up: If the rot13 flag is true, wrap the reader -we received into a rotate13 and proceed. Note that the interface variables -are values, not pointers: the argument is of type reader, not *reader, -even though under the covers it holds a pointer to a struct. -

-Here it is in action: -

-

-$ echo abcdefghijklmnopqrstuvwxyz | ./cat
-abcdefghijklmnopqrstuvwxyz
-$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
-nopqrstuvwxyzabcdefghijklm
-$
-
-

-Fans of dependency injection may take cheer from how easily interfaces -allow us to substitute the implementation of a file descriptor. -

-Interfaces are a distinctive feature of Go. An interface is implemented by a -type if the type implements all the methods declared in the interface. -This means -that a type may implement an arbitrary number of different interfaces. -There is no type hierarchy; things can be much more ad hoc, -as we saw with rot13. The type file.File implements reader; it could also -implement a writer, or any other interface built from its methods that -fits the current situation. Consider the empty interface -

-

-type Empty interface {}
-
-

-Every type implements the empty interface, which makes it -useful for things like containers. -

-

Sorting

-

-Interfaces provide a simple form of polymorphism. They completely -separate the definition of what an object does from how it does it, allowing -distinct implementations to be represented at different times by the -same interface variable. -

-As an example, consider this simple sort algorithm taken from progs/sort.go: -

-

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)
-        }
-    }
-}
-

-The code needs only three methods, which we wrap into sort's Interface: -

-

type Interface interface {
-    Len() int
-    Less(i, j int) bool
-    Swap(i, j int)
-}
-

-We can apply Sort to any type that implements Len, Less, and Swap. -The sort package includes the necessary methods to allow sorting of -arrays of integers, strings, etc.; here's the code for arrays of int -

-

type IntSlice []int
-
-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] }
-

-Here we see methods defined for non-struct types. You can define methods -for any type you define and name in your package. -

-And now a routine to test it out, from progs/sortmain.go. This -uses a function in the sort package, omitted here for brevity, -to test that the result is sorted. -

-

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")
-    }
-}
-

-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: -

-

type day struct {
-    num       int
-    shortName string
-    longName  string
-}
-
-type dayArray struct {
-    data []*day
-}
-
-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] }
-

-

-

Printing

-

-The examples of formatted printing so far have been modest. In this section -we'll talk about how formatted I/O can be done well in Go. -

-We've seen simple uses of the package fmt, which -implements Printf, Fprintf, and so on. -Within the fmt package, Printf is declared with this signature: -

-

-Printf(format string, v ...interface{}) (n int, errno error)
-
-

-The token ... introduces a variable-length argument list that in C would -be handled using the stdarg.h macros. -In Go, variadic functions are passed a slice of the arguments of the -specified type. In Printf's case, the declaration says ...interface{} -so the actual type is a slice of empty interface values, []interface{}. -Printf can examine the arguments by iterating over the slice -and, for each element, using a type switch or the reflection library -to interpret the value. -It's off topic here but such run-time type analysis -helps explain some of the nice properties of Go's Printf, -due to the ability of Printf to discover the type of its arguments -dynamically. -

-For example, in C each format must correspond to the type of its -argument. It's easier in many cases in Go. Instead of %llud you -can just say %d; Printf knows the size and signedness of the -integer and can do the right thing for you. The snippet -

-

    var u64 uint64 = 1<<64 - 1
-    fmt.Printf("%d %d\n", u64, int64(u64))
-

-prints -

-

-18446744073709551615 -1
-
-

-In fact, if you're lazy the format %v will print, in a simple -appropriate style, any value, even an array or structure. The output of -

-

    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)
-

-is -

-

-18446744073709551615 {77 Sunset Strip} [1 2 3 4]
-
-

-You can drop the formatting altogether if you use Print or Println -instead of Printf. Those routines do fully automatic formatting. -The Print function just prints its elements out using the equivalent -of %v while Println inserts spaces between arguments -and adds a newline. The output of each of these two lines is identical -to that of the Printf call above. -

-

    fmt.Print(u64, " ", t, " ", a, "\n")
-    fmt.Println(u64, t, a)
-

-If you have your own type you'd like Printf or Print to format, -just give it a String method that returns a string. The print -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. -

-

type testType struct {
-    a int
-    b string
-}
-
-func (t *testType) String() string {
-    return fmt.Sprint(t.a) + " " + t.b
-}
-
-func main() {
-    t := &testType{77, "Sunset Strip"}
-    fmt.Println(t)
-}
-

-Since *testType has a String method, the -default formatter for that type will use it and produce the output -

-

-77 Sunset Strip
-
-

-Observe that the String method calls Sprint (the obvious Go -variant that returns a string) to do its formatting; special formatters -can use the fmt library recursively. -

-Another feature of Printf is that the format %T will print a string -representation of the type of a value, which can be handy when debugging -polymorphic code. -

-It's possible to write full custom print formats with flags and precisions -and such, but that's getting a little off the main thread so we'll leave it -as an exploration exercise. -

-You might ask, though, how Printf can tell whether a type implements -the String method. Actually what it does is ask if the value can -be converted to an interface variable that implements the method. -Schematically, given a value v, it does this: -

-

-

-type Stringer interface {
-    String() string
-}
-
-

-

-s, ok := v.(Stringer)  // Test whether v implements "String()"
-if ok {
-    result = s.String()
-} else {
-    result = defaultOutput(v)
-}
-
-

-The code uses a ``type assertion'' (v.(Stringer)) to test if the value stored in -v satisfies the Stringer interface; if it does, s -will become an interface variable implementing the method and ok will -be true. We then use the interface variable to call the method. -(The ''comma, ok'' pattern is a Go idiom used to test the success of -operations such as type conversion, map update, communications, and so on, -although this is the only appearance in this tutorial.) -If the value does not satisfy the interface, ok will be false. -

-In this snippet the name Stringer follows the convention that we add ''[e]r'' -to interfaces describing simple method sets like this. -

-A related interface is that defined by the error builtin type, which is just -

-

-type error interface {
-    Error() string
-}
-
-

-Other than the method name (Error vs. String), this looks like -a Stringer; the different name guarantees that types that implement Stringer -don't accidentally satisfy the error interface. -Naturally, Printf and its relatives recognize the error interface, -just as they do Stringer, -so it's trivial to print an error as a string. -

-One last wrinkle. To complete the suite, besides Printf etc. and Sprintf -etc., there are also Fprintf etc. Unlike in C, Fprintf's first argument is -not a file. Instead, it is a variable of type io.Writer, which is an -interface type defined in the io library: -

-

-type Writer interface {
-    Write(p []byte) (n int, err error)
-}
-
-

-(This interface is another conventional name, this time for Write; there are also -io.Reader, io.ReadWriter, and so on.) -Thus you can call Fprintf on any type that implements a standard Write -method, not just files but also network channels, buffers, whatever -you want. -

-

Prime numbers

-

-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. -

-A classic program in the style is a prime sieve. -(The sieve of Eratosthenes is computationally 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 -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 -so far, and the next number to pop out is the next prime, which triggers -the creation of the next filter in the chain. -

-Here's a flow diagram; each box represents a filter element whose -creation is triggered by the first number that flowed from the -elements before it. -

-
-

-      -

-
-

-To create a stream of integers, we use a Go channel, which, -borrowing from CSP's descendants, represents a communications -channel that can connect two concurrent computations. -In Go, channel variables are references to a run-time object that -coordinates the communication; as with maps and slices, use -make to create a new channel. -

-Here is the first function in progs/sieve.go: -

-

// 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'.
-    }
-}
-

-The generate function sends the sequence 2, 3, 4, 5, ... to its -argument channel, ch, using the binary communications operator <-. -Channel operations block, so if there's no recipient for the value on ch, -the send operation will wait until one becomes available. -

-The filter function has three arguments: an input channel, an output -channel, and a prime number. It copies values from the input to the -output, discarding anything divisible by the prime. The unary communications -operator <- (receive) retrieves the next value on the channel. -

-

// 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'.
-        }
-    }
-}
-

-The generator and filters execute concurrently. Go has -its own model of process/threads/light-weight processes/coroutines, -so to avoid notational confusion we call concurrently executing -computations in Go goroutines. To start a goroutine, -invoke the function, prefixing the call with the keyword go; -this starts the function running in parallel with the current -computation but in the same address space: -

-

-go sum(hugeArray) // calculate sum in the background
-
-

-If you want to know when the calculation is done, pass a channel -on which it can report back: -

-

-ch := make(chan int)
-go sum(hugeArray, ch)
-// ... do something else for a while
-result := <-ch  // wait for, and retrieve, result
-
-

-Back to our prime sieve. Here's how the sieve pipeline is stitched -together: -

-

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
-    }
-}
-

-The first line of main creates the initial channel to pass to generate, which it -then starts up. As each prime pops out of the channel, a new filter -is added to the pipeline and its output becomes the new value -of ch. -

-The sieve program can be tweaked to use a pattern common -in this style of programming. Here is a variant version -of generate, from progs/sieve1.go: -

-

func generate() chan int {
-    ch := make(chan int)
-    go func() {
-        for i := 2; ; i++ {
-            ch <- i
-        }
-    }()
-    return ch
-}
-

-This version does all the setup internally. It creates the output -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. -

-The function literal notation used in the go statement allows us to construct an -anonymous function and invoke it on the spot. Notice that the local -variable ch is available to the function literal and lives on even -after generate returns. -

-The same change can be made to 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
-}
-

-The sieve 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: -

-

func sieve() chan int {
-    out := make(chan int)
-    go func() {
-        ch := generate()
-        for {
-            prime := <-ch
-            out <- prime
-            ch = filter(ch, prime)
-        }
-    }()
-    return out
-}
-

-Now main's interface to the prime sieve is a channel of primes: -

-

func main() {
-    primes := sieve()
-    for i := 0; i < 100; i++ { // Print the first hundred primes.
-        fmt.Println(<-primes)
-    }
-}
-

-

Multiplexing

-

-With channels, it's possible to serve multiple independent client goroutines without -writing an explicit multiplexer. The trick is to send the server a channel in the message, -which it will then use to reply to the original sender. -A realistic client-server program is a lot of code, so here is a very simple substitute -to illustrate the idea. It starts by defining a request type, which embeds a channel -that will be used for the reply. -

-

type request struct {
-    a, b   int
-    replyc chan int
-}
-

-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: -

-

type binOp func(a, b int) int
-
-func run(op binOp, req *request) {
-    reply := op(req.a, req.b)
-    req.replyc <- reply
-}
-

-The type declaration makes binOp represent a function taking two integers and -returning a third. -

-The server routine loops forever, receiving requests and, to avoid blocking due to -a long-running operation, starting a goroutine to do the actual work. -

-

func server(op binOp, service <-chan *request) {
-    for {
-        req := <-service
-        go run(op, req) // don't wait for it
-    }
-}
-

-There's a new feature in the signature of server: the type of the -service channel specifies the direction of communication. -A channel of plain chan type can be used both for sending and receiving. -However, the type used when declaring a channel can be decorated with an arrow to -indicate that the channel can be used only to send (chan<-) or to -receive (<-chan) data. -The arrow points towards or away from the chan to indicate whether data flows into or out of -the channel. -In the server function, service <-chan *request is a "receive only" channel -that the function can use only to read new requests. -

-We instantiate a server in a familiar way, starting it and returning a channel -connected to it: -

-

func startServer(op binOp) chan<- *request {
-    req := make(chan *request)
-    go server(op, req)
-    return req
-}
-

-The returned channel is send only, even though the channel was created bidirectionally. -The read end is passed to server, while the send end is returned -to the caller of startServer, so the two halves of the channel -are distinguished, just as we did in startServer. -

-Bidirectional channels can be assigned to unidirectional channels but not the -other way around, so if you annotate your channel directions when you declare -them, such as in function signatures, the type system can help you set up and -use channels correctly. -Note that it's pointless to make unidirectional channels, since you can't -use them to communicate. Their purpose is served by variables assigned from bidirectional channels -to distinguish the input and output halves. -

-Here's a simple test. It starts a server with an addition operator and sends out -N requests without waiting for the replies. Only after all the requests are sent -does it check the results. -

-

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")
-}
-

-One annoyance with this program is that it doesn't shut down the server cleanly; when main returns -there are a number of lingering goroutines blocked on communication. To solve this, -we can provide a second, quit channel to the server: -

-

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
-}
-

-It passes the quit channel to the server function, which uses it like this: -

-

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
-        }
-    }
-}
-

-Inside server, the select statement chooses which of the multiple communications -listed by its cases can proceed. If all are blocked, it waits until one can proceed; if -multiple can proceed, it chooses one at random. In this instance, the select allows -the server to honor requests until it receives a quit message, at which point it -returns, terminating its execution. -

-

-All that's left is to strobe the quit channel -at the end of main: -

-

    adder, quit := startServer(func(a, b int) int { return a + b })
-... -
    quit <- true
-

-There's a lot more to Go programming and concurrent programming in general but this -quick tour should give you some of the basics. diff --git a/doc/go_tutorial.tmpl b/doc/go_tutorial.tmpl deleted file mode 100644 index 33189189e4..0000000000 --- a/doc/go_tutorial.tmpl +++ /dev/null @@ -1,1040 +0,0 @@ - -{{donotedit}} - -

Introduction

-

-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 -guide to the language; at the moment the document closest to that is the -language specification. -After you've read this tutorial, you should look at -Effective Go, -which digs deeper into how the language is used and -talks about the style and idioms of programming in Go. -An interactive introduction to Go is available, called -A Tour of Go. -

-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 -checked into the repository in the directory /doc/progs/. -

-

Hello, World

-

-Let's start in the usual way: -

-{{code "progs/helloworld.go" `/package/` "$"}} -

-Every Go source file declares, using a package statement, which package it's part of. -It may also import other packages to use their facilities. -This program imports the package fmt to gain access to -our old, now capitalized and package-qualified, friend, fmt.Printf. -

-Functions are introduced with the func keyword. -The main package's main function is where the program starts running (after -any initialization). -

-String constants can contain Unicode characters, encoded in UTF-8. -(In fact, Go source files are defined to be encoded in UTF-8.) -

-The comment convention is the same as in C++: -

-

-/* ... */
-// ...
-
-

-Later we'll have much more to say about printing. -

-

Semicolons

-

-You might have noticed that our program has no semicolons. In Go -code, the only place you typically see semicolons is separating the -clauses of for loops and the like; they are not necessary after -every statement. -

-In fact, what happens is that the formal language uses semicolons, -much as in C or Java, but they are inserted automatically -at the end of every line that looks like the end of a statement. You -don't need to type them yourself. -

-For details about how this is done you can see the language -specification, but in practice all you need to know is that you -never need to put a semicolon at the end of a line. (You can put -them in if you want to write multiple statements per line.) As an -extra help, you can also leave out a semicolon immediately before -a closing brace. -

-This approach makes for clean-looking, semicolon-free code. The -one surprise is that it's important to put the opening -brace of a construct such as an if statement on the same line as -the if; if you don't, there are situations that may not compile -or may give the wrong result. The language forces the brace style -to some extent. -

-

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

-

-Next up, here's a version of the Unix utility echo(1): -

-{{code "progs/echo.go" `/package/` "$"}} -

-This program is small but it's doing a number of new things. In the last example, -we saw func introduce a function. The keywords var, const, and type -(not used yet) also introduce declarations, as does import. -Notice that we can group declarations of the same sort into -parenthesized lists, one item per line, as in the import and const clauses here. -But it's not necessary to do so; we could have said -

-

-const Space = " "
-const Newline = "\n"
-
-

-This program imports the "os" package to access its Stdout variable, of type -*os.File. The import statement is actually a declaration: in its general form, -as used in our ``hello world'' program, -it names the identifier (fmt) -that will be used to access members of the package imported from the file ("fmt"), -found in the current directory or in a standard location. -In this program, though, we've dropped the explicit name from the imports; by default, -packages are imported using the name defined by the imported package, -which by convention is of course the file name itself. Our ``hello world'' program -could have said just import "fmt". -

-You can specify your -own import names if you want but it's only necessary if you need to resolve -a naming conflict. -

-Given os.Stdout we can use its WriteString method to print the string. -

-After importing the flag package, we use a var declaration -to create and initialize a global variable, called omitNewline, -to hold the value of echo's -n flag. -The variable has type *bool, pointer to bool. -

-In main.main, we parse the arguments (the call to flag.Parse) and then create a local -string variable with which to build the output. -

-The declaration statement has the form -

-

-var s string = ""
-
-

-This is the var keyword, followed by the name of the variable, followed by -its type, followed by an equals sign and an initial value for the variable. -

-Go tries to be terse, and this declaration could be shortened. Since the -string constant is of type string, we don't have to tell the compiler that. -We could write -

-

-var s = ""
-
-

-or we could go even shorter and write the idiom -

-

-s := ""
-
-

-The := operator is used a lot in Go to represent an initializing declaration. -There's one in the for clause on the next line: -

-{{code "progs/echo.go" `/for/`}} -

-The flag package has parsed the arguments and left the non-flag arguments -in a list that can be iterated over in the obvious way. -

-The Go for statement differs from that of C in a number of ways. First, -it's the only looping construct; there is no while or do. Second, -there are no parentheses on the clause, but the braces on the body -are mandatory. The same applies to the if and switch statements. -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 arguments and separating spaces. After the loop, if the -n flag is not -set, the program appends a newline. Finally, it writes the result. -

-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 -''success''; if you want to signal an erroneous return, call -

-

-os.Exit(1)
-
-

-The os package contains other essentials for getting -started; for instance, os.Args is a slice used by the -flag package to access the command-line arguments. -

-

An Interlude about Types

-

-Go has some familiar types such as int and uint (unsigned int), which represent -values of the ''appropriate'' size for the machine. It also defines -explicitly-sized types such as int8, float64, and so on, plus -unsigned integer types such as uint, uint32, etc. -These are distinct types; even if int and int32 are both 32 bits in size, -they are not the same type. There is also a byte synonym for -uint8, which is the element type for strings. -

-Floating-point types are always sized: float32 and float64, -plus complex64 (two float32s) and complex128 -(two float64s). Complex numbers are outside the -scope of this tutorial. -

-Speaking of string, that's a built-in type as well. Strings are -immutable values—they are not just arrays of byte values. -Once you've built a string value, you can't change it, although -of course you can change a string variable simply by -reassigning it. This snippet from strings.go is legal code: -

-{{code "progs/strings.go" `/hello/` `/ciao/`}} -

-However the following statements are illegal because they would modify -a string value: -

-

-s[0] = 'x'
-(*p)[1] = 'y'
-
-

-In C++ terms, Go strings are a bit like const strings, while pointers -to strings are analogous to const string references. -

-Yes, there are pointers. However, Go simplifies their use a little; -read on. -

-Arrays are declared like this: -

-

-var arrayOfInt [10]int
-
-

-Arrays, like strings, are values, but they are mutable. This differs -from C, in which arrayOfInt would be usable as a pointer to int. -In Go, since arrays are values, it's meaningful (and useful) to talk -about pointers to arrays. -

-The size of the array is part of its type; however, one can declare -a slice variable to hold a reference to any array, of any size, -with the same element type. -A slice -expression has the form a[low : high], representing -the internal array indexed from low through high-1; the resulting -slice is indexed from 0 through high-low-1. -In short, slices look a lot like arrays but with -no explicit size ([] vs. [10]) and they reference a segment of -an underlying, usually anonymous, regular array. Multiple slices -can share data if they represent pieces of the same array; -multiple arrays can never share data. -

-Slices are much more common in Go programs than -regular arrays; they're more flexible, have reference semantics, -and are efficient. What they lack is the precise control of storage -layout of a regular array; if you want to have a hundred elements -of an array stored within your structure, you should use a regular -array. To create one, use a compound value constructor—an -expression formed -from a type followed by a brace-bounded expression like this: -

-

-[3]int{1,2,3}
-
-

-In this case the constructor builds an array of 3 ints. -

-When passing an array to a function, you almost always want -to declare the formal parameter to be a slice. When you call -the function, slice the array to create -(efficiently) a slice reference and pass that. -By default, the lower and upper bounds of a slice match the -ends of the existing object, so the concise notation [:] -will slice the whole array. -

-Using slices one can write this function (from sum.go): -

-{{code "progs/sum.go" `/sum/` `/^}/`}} -

-Note how the return type (int) is defined for sum by stating it -after the parameter list. -

-To call the function, we slice the array. This code (we'll show -a simpler way in a moment) constructs -an array and slices it: -

-

-x := [3]int{1,2,3}
-s := sum(x[:])
-
-

-If you are creating a regular array but want the compiler to count the -elements for you, use ... as the array size: -

-

-x := [...]int{1,2,3}
-s := sum(x[:])
-
-

-That's fussier than necessary, though. -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: -

-

-s := sum([]int{1,2,3})
-
-

-There are also maps, which you can initialize like this: -

-

-m := map[string]int{"one":1 , "two":2}
-
-

-The built-in function len, which returns number of elements, -makes its first appearance in sum. It works on strings, arrays, -slices, maps, and channels. -

-By the way, another thing that works on strings, arrays, slices, maps -and channels is the range clause on for loops. Instead of writing -

-

-for i := 0; i < len(a); i++ { ... }
-
-

-to loop over the elements of a slice (or map or ...) , we could write -

-

-for i, v := range a { ... }
-
-

-This assigns i to the index and v to the value of the successive -elements of the target of the range. See -Effective Go -for more examples of its use. -

-

-

An Interlude about Allocation

-

-Most types in Go are values. If you have an int or a struct -or an array, assignment -copies the contents of the object. -To allocate a new variable, use the built-in function new, which -returns a pointer to the allocated storage. -

-

-type T struct { a, b int }
-var t *T = new(T)
-
-

-or the more idiomatic -

-

-t := new(T)
-
-

-Some types—maps, slices, and channels (see below)—have reference semantics. -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 -types you want to use the built-in function make: -

-

-m := make(map[string]int)
-
-

-This statement initializes a new map ready to store entries. -If you just declare the map, as in -

-

-var m map[string]int
-
-

-it creates a nil reference that cannot hold anything. To use the map, -you must first initialize the reference using make or by assignment from an -existing map. -

-Note that new(T) returns type *T while make(T) returns type -T. If you (mistakenly) allocate a reference object with new rather than make, -you receive a pointer to a nil reference, equivalent to -declaring an uninitialized variable and taking its address. -

-

An Interlude about Constants

-

-Although integers come in lots of sizes in Go, integer constants do not. -There are no constants like 0LL or 0x0UL. Instead, integer -constants are evaluated as large-precision values that -can overflow only when they are assigned to an integer variable with -too little precision to represent the value. -

-

-const hardEight = (1 << 100) >> 97  // legal
-
-

-There are nuances that deserve redirection to the legalese of the -language specification but here are some illustrative examples: -

-

-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
-
-

-Conversions only work for simple cases such as converting ints of one -sign or size to another and between integers and floating-point numbers, -plus a couple of other instances outside the scope of a tutorial. -There are no automatic numeric conversions of any kind in Go, -other than that of making constants have concrete size and type when -assigned to a variable. -

-

An I/O Package

-

-Next we'll look at a simple package for doing Unix file I/O with an -open/close/read/write interface. -Here's the start of file.go: -

-{{code "progs/file.go" `/package/` `/^}/`}} -

-The first few lines declare the name of the -package—file—and then import two packages. The os -package hides the differences -between various operating systems to give a consistent view of files and -so on; here we're going to use its error handling utilities -and reproduce the rudiments of its file I/O. -

-The other item is the low-level, external syscall package, which provides -a primitive interface to the underlying operating system's calls. -The syscall package is very system-dependent, and the way it's -used here works only on Unix-like systems, -but the general ideas explored here apply broadly. -(A Windows version is available in -file_windows.go.) -

-Next is a type definition: the type keyword introduces a type declaration, -in this case a data structure called File. -To make things a little more interesting, our File includes the name of the file -that the file descriptor refers to. -

-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 -simple: if a name (of a top-level type, function, method, constant or variable, or of -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 -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 the case of File, all its fields are lower case and so invisible to users, but we -will soon give it some exported, upper-case methods. -

-First, though, here is a factory to create a File: -

-{{code "progs/file.go" `/newFile/` `/^}/`}} -

-This returns a pointer to a new File structure with the file descriptor and name -filled in. This code uses Go's notion of a ''composite literal'', analogous to -the ones used to build maps and arrays, to construct a new heap-allocated -object. We could write -

-

-n := new(File)
-n.fd = fd
-n.name = name
-return n
-
-

-but for simple structures like File it's easier to return the address of a -composite literal, as is done here in the return statement from newFile. -

-We can use the factory to construct some familiar, exported variables of type *File: -

-{{code "progs/file.go" `/var/` `/^\)/`}} -

-The newFile function was not exported because it's internal. The proper, -exported factory to use is OpenFile (we'll explain that name in a moment): -

-{{code "progs/file.go" `/func.OpenFile/` `/^}/`}} -

-There are a number of new things in these few lines. First, OpenFile returns -multiple values, a File and an error (more about errors in a moment). -We declare the -multi-value return as a parenthesized list of declarations; syntactically -they look just like a second parameter list. The function -syscall.Open -also has a multi-value return, which we can grab with the multi-variable -declaration on the first line; it declares r and e to hold the two values, -both of type int (although you'd have to look at the syscall package -to see that). Finally, OpenFile returns two values: a pointer to the new File -and the error. If syscall.Open fails, the file descriptor r will -be negative and newFile will return nil. -

-About those errors: The Go language includes a general notion of an error: -a pre-defined type error with properties (described below) -that make it a good basis for representing and handling errors. -It's a good idea to use its facility in your own interfaces, as we do here, for -consistent error handling throughout Go code. In Open we use a -conversion to translate Unix's integer errno value into the integer type -os.Errno, which is an implementation of error -

-Why OpenFile and not Open? To mimic Go's os package, which -our exercise is emulating. The os package takes the opportunity -to make the two commonest cases - open for read and create for -write - the simplest, just Open and Create. OpenFile is the -general case, analogous to the Unix system call Open. Here is -the implementation of our Open and Create; they're trivial -wrappers that eliminate common errors by capturing -the tricky standard arguments to open and, especially, to create a file: -

-{{code "progs/file.go" `/^const/` `/^}/`}} -

-{{code "progs/file.go" `/func.Create/` `/^}/`}} -

-Back to our main story. -Now that we can build Files, we can write methods for them. To declare -a method of a type, we define a function to have an explicit receiver -of that type, placed -in parentheses before the function name. Here are some methods for *File, -each of which declares a receiver variable file. -

-{{code "progs/file.go" `/Close/` "$"}} -

-There is no implicit this and the receiver variable must be used to access -members of the structure. Methods are not declared within -the struct declaration itself. The struct declaration defines only data members. -In fact, methods can be created for almost any type you name, such as an integer or -array, not just for structs. We'll see an example with arrays later. -

-The String method is so called because of a printing convention we'll -describe later. -

-The methods use the public variable os.ErrInvalid to return the (error -version of the) Unix error code EINVAL. The os library defines a standard -set of such error values. -

-We can now use our new package: -

-{{code "progs/helloworld3.go" `/package/` "$"}} -

-The ''./'' in the import of ''./file'' tells the compiler -to use our own package rather than -something from the directory of installed packages. -(Also, ''file.go'' must be compiled before we can import the -package.) -

-Now we can compile and run the program. On Unix, this would be the result: -

-

-$ 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
-$
-
-

-

Rotting cats

-

-Building on the file package, here's a simple version of the Unix utility cat(1), -progs/cat.go: -

-{{code "progs/cat.go" `/package/` "$"}} -

-By now this should be easy to follow, but the switch statement introduces some -new features. Like a for loop, an if or switch can include an -initialization statement. The switch statement in cat uses one to create variables -nr and er to hold the return values from the call to f.Read. (The if a few lines later -has the same idea.) The switch 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 -they all have the same type. -

-Since the switch value is just true, we could leave it off—as is also -the situation -in a for statement, a missing value means true. In fact, such a switch -is a form of if-else chain. While we're here, it should be mentioned that in -switch statements each case has an implicit break. -

-The argument to file.Stdout.Write is created by slicing the array buf. -Slices provide the standard Go way to handle I/O buffers. -

-Now let's make a variant of cat that optionally does rot13 on its input. -It's easy to do by just processing the bytes, but instead we will exploit -Go's notion of an interface. -

-The cat subroutine uses only two methods of f: Read and String, -so let's start by defining an interface that has exactly those two methods. -Here is code from progs/cat_rot13.go: -

-{{code "progs/cat_rot13.go" `/type.reader/` `/^}/`}} -

-Any type that has the two methods of reader—regardless of whatever -other methods the type may also have—is said to implement the -interface. Since file.File implements these methods, it implements the -reader interface. We could tweak the cat subroutine to accept a reader -instead of a *file.File and it would work just fine, but let's embellish a little -first by writing a second type that implements reader, one that wraps an -existing reader and does rot13 on the data. To do this, we just define -the type and implement the methods and with no other bookkeeping, -we have a second implementation of the reader interface. -

-{{code "progs/cat_rot13.go" `/type.rotate13/` `/end.of.rotate13/`}} -

-(The rot13 function called in Read is trivial and not worth reproducing here.) -

-To use the new feature, we define a flag: -

-{{code "progs/cat_rot13.go" `/rot13Flag/`}} -

-and use it from within a mostly unchanged cat function: -

-{{code "progs/cat_rot13.go" `/func.cat/` `/^}/`}} -

-(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.) -The if at the top of cat sets it all up: If the rot13 flag is true, wrap the reader -we received into a rotate13 and proceed. Note that the interface variables -are values, not pointers: the argument is of type reader, not *reader, -even though under the covers it holds a pointer to a struct. -

-Here it is in action: -

-

-$ echo abcdefghijklmnopqrstuvwxyz | ./cat
-abcdefghijklmnopqrstuvwxyz
-$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
-nopqrstuvwxyzabcdefghijklm
-$
-
-

-Fans of dependency injection may take cheer from how easily interfaces -allow us to substitute the implementation of a file descriptor. -

-Interfaces are a distinctive feature of Go. An interface is implemented by a -type if the type implements all the methods declared in the interface. -This means -that a type may implement an arbitrary number of different interfaces. -There is no type hierarchy; things can be much more ad hoc, -as we saw with rot13. The type file.File implements reader; it could also -implement a writer, or any other interface built from its methods that -fits the current situation. Consider the empty interface -

-

-type Empty interface {}
-
-

-Every type implements the empty interface, which makes it -useful for things like containers. -

-

Sorting

-

-Interfaces provide a simple form of polymorphism. They completely -separate the definition of what an object does from how it does it, allowing -distinct implementations to be represented at different times by the -same interface variable. -

-As an example, consider this simple sort algorithm taken from progs/sort.go: -

-{{code "progs/sort.go" `/func.Sort/` `/^}/`}} -

-The code needs only three methods, which we wrap into sort's Interface: -

-{{code "progs/sort.go" `/interface/` `/^}/`}} -

-We can apply Sort to any type that implements Len, Less, and Swap. -The sort package includes the necessary methods to allow sorting of -arrays of integers, strings, etc.; here's the code for arrays of int -

-{{code "progs/sort.go" `/type.*IntSlice/` `/Swap/`}} -

-Here we see methods defined for non-struct types. You can define methods -for any type you define and name in your package. -

-And now a routine to test it out, from progs/sortmain.go. This -uses a function in the sort package, omitted here for brevity, -to test that the result is sorted. -

-{{code "progs/sortmain.go" `/func.ints/` `/^}/`}} -

-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: -

-{{code "progs/sortmain.go" `/type.day/` `/Swap/`}} -

-

-

Printing

-

-The examples of formatted printing so far have been modest. In this section -we'll talk about how formatted I/O can be done well in Go. -

-We've seen simple uses of the package fmt, which -implements Printf, Fprintf, and so on. -Within the fmt package, Printf is declared with this signature: -

-

-Printf(format string, v ...interface{}) (n int, errno error)
-
-

-The token ... introduces a variable-length argument list that in C would -be handled using the stdarg.h macros. -In Go, variadic functions are passed a slice of the arguments of the -specified type. In Printf's case, the declaration says ...interface{} -so the actual type is a slice of empty interface values, []interface{}. -Printf can examine the arguments by iterating over the slice -and, for each element, using a type switch or the reflection library -to interpret the value. -It's off topic here but such run-time type analysis -helps explain some of the nice properties of Go's Printf, -due to the ability of Printf to discover the type of its arguments -dynamically. -

-For example, in C each format must correspond to the type of its -argument. It's easier in many cases in Go. Instead of %llud you -can just say %d; Printf knows the size and signedness of the -integer and can do the right thing for you. The snippet -

-{{code "progs/print.go" 10 11}} -

-prints -

-

-18446744073709551615 -1
-
-

-In fact, if you're lazy the format %v will print, in a simple -appropriate style, any value, even an array or structure. The output of -

-{{code "progs/print.go" 14 20}} -

-is -

-

-18446744073709551615 {77 Sunset Strip} [1 2 3 4]
-
-

-You can drop the formatting altogether if you use Print or Println -instead of Printf. Those routines do fully automatic formatting. -The Print function just prints its elements out using the equivalent -of %v while Println inserts spaces between arguments -and adds a newline. The output of each of these two lines is identical -to that of the Printf call above. -

-{{code "progs/print.go" 21 22}} -

-If you have your own type you'd like Printf or Print to format, -just give it a String method that returns a string. The print -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. -

-{{code "progs/print_string.go" 9 "$"}} -

-Since *testType has a String method, the -default formatter for that type will use it and produce the output -

-

-77 Sunset Strip
-
-

-Observe that the String method calls Sprint (the obvious Go -variant that returns a string) to do its formatting; special formatters -can use the fmt library recursively. -

-Another feature of Printf is that the format %T will print a string -representation of the type of a value, which can be handy when debugging -polymorphic code. -

-It's possible to write full custom print formats with flags and precisions -and such, but that's getting a little off the main thread so we'll leave it -as an exploration exercise. -

-You might ask, though, how Printf can tell whether a type implements -the String method. Actually what it does is ask if the value can -be converted to an interface variable that implements the method. -Schematically, given a value v, it does this: -

-

-

-type Stringer interface {
-    String() string
-}
-
-

-

-s, ok := v.(Stringer)  // Test whether v implements "String()"
-if ok {
-    result = s.String()
-} else {
-    result = defaultOutput(v)
-}
-
-

-The code uses a ``type assertion'' (v.(Stringer)) to test if the value stored in -v satisfies the Stringer interface; if it does, s -will become an interface variable implementing the method and ok will -be true. We then use the interface variable to call the method. -(The ''comma, ok'' pattern is a Go idiom used to test the success of -operations such as type conversion, map update, communications, and so on, -although this is the only appearance in this tutorial.) -If the value does not satisfy the interface, ok will be false. -

-In this snippet the name Stringer follows the convention that we add ''[e]r'' -to interfaces describing simple method sets like this. -

-A related interface is that defined by the error builtin type, which is just -

-

-type error interface {
-    Error() string
-}
-
-

-Other than the method name (Error vs. String), this looks like -a Stringer; the different name guarantees that types that implement Stringer -don't accidentally satisfy the error interface. -Naturally, Printf and its relatives recognize the error interface, -just as they do Stringer, -so it's trivial to print an error as a string. -

-One last wrinkle. To complete the suite, besides Printf etc. and Sprintf -etc., there are also Fprintf etc. Unlike in C, Fprintf's first argument is -not a file. Instead, it is a variable of type io.Writer, which is an -interface type defined in the io library: -

-

-type Writer interface {
-    Write(p []byte) (n int, err error)
-}
-
-

-(This interface is another conventional name, this time for Write; there are also -io.Reader, io.ReadWriter, and so on.) -Thus you can call Fprintf on any type that implements a standard Write -method, not just files but also network channels, buffers, whatever -you want. -

-

Prime numbers

-

-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. -

-A classic program in the style is a prime sieve. -(The sieve of Eratosthenes is computationally 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 -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 -so far, and the next number to pop out is the next prime, which triggers -the creation of the next filter in the chain. -

-Here's a flow diagram; each box represents a filter element whose -creation is triggered by the first number that flowed from the -elements before it. -

-
-

-      -

-
-

-To create a stream of integers, we use a Go channel, which, -borrowing from CSP's descendants, represents a communications -channel that can connect two concurrent computations. -In Go, channel variables are references to a run-time object that -coordinates the communication; as with maps and slices, use -make to create a new channel. -

-Here is the first function in progs/sieve.go: -

-{{code "progs/sieve.go" `/Send/` `/^}/`}} -

-The generate function sends the sequence 2, 3, 4, 5, ... to its -argument channel, ch, using the binary communications operator <-. -Channel operations block, so if there's no recipient for the value on ch, -the send operation will wait until one becomes available. -

-The filter function has three arguments: an input channel, an output -channel, and a prime number. It copies values from the input to the -output, discarding anything divisible by the prime. The unary communications -operator <- (receive) retrieves the next value on the channel. -

-{{code "progs/sieve.go" `/Copy.the/` `/^}/`}} -

-The generator and filters execute concurrently. Go has -its own model of process/threads/light-weight processes/coroutines, -so to avoid notational confusion we call concurrently executing -computations in Go goroutines. To start a goroutine, -invoke the function, prefixing the call with the keyword go; -this starts the function running in parallel with the current -computation but in the same address space: -

-

-go sum(hugeArray) // calculate sum in the background
-
-

-If you want to know when the calculation is done, pass a channel -on which it can report back: -

-

-ch := make(chan int)
-go sum(hugeArray, ch)
-// ... do something else for a while
-result := <-ch  // wait for, and retrieve, result
-
-

-Back to our prime sieve. Here's how the sieve pipeline is stitched -together: -

-{{code "progs/sieve.go" `/func.main/` `/^}/`}} -

-The first line of main creates the initial channel to pass to generate, which it -then starts up. As each prime pops out of the channel, a new filter -is added to the pipeline and its output becomes the new value -of ch. -

-The sieve program can be tweaked to use a pattern common -in this style of programming. Here is a variant version -of generate, from progs/sieve1.go: -

-{{code "progs/sieve1.go" `/func.generate/` `/^}/`}} -

-This version does all the setup internally. It creates the output -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. -

-The function literal notation used in the go statement allows us to construct an -anonymous function and invoke it on the spot. Notice that the local -variable ch is available to the function literal and lives on even -after generate returns. -

-The same change can be made to filter: -

-{{code "progs/sieve1.go" `/func.filter/` `/^}/`}} -

-The sieve 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: -

-{{code "progs/sieve1.go" `/func.sieve/` `/^}/`}} -

-Now main's interface to the prime sieve is a channel of primes: -

-{{code "progs/sieve1.go" `/func.main/` `/^}/`}} -

-

Multiplexing

-

-With channels, it's possible to serve multiple independent client goroutines without -writing an explicit multiplexer. The trick is to send the server a channel in the message, -which it will then use to reply to the original sender. -A realistic client-server program is a lot of code, so here is a very simple substitute -to illustrate the idea. It starts by defining a request type, which embeds a channel -that will be used for the reply. -

-{{code "progs/server.go" `/type.request/` `/^}/`}} -

-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 "progs/server.go" `/type.binOp/` `/^}/`}} -

-The type declaration makes binOp represent a function taking two integers and -returning a third. -

-The server routine loops forever, receiving requests and, to avoid blocking due to -a long-running operation, starting a goroutine to do the actual work. -

-{{code "progs/server.go" `/func.server/` `/^}/`}} -

-There's a new feature in the signature of server: the type of the -service channel specifies the direction of communication. -A channel of plain chan type can be used both for sending and receiving. -However, the type used when declaring a channel can be decorated with an arrow to -indicate that the channel can be used only to send (chan<-) or to -receive (<-chan) data. -The arrow points towards or away from the chan to indicate whether data flows into or out of -the channel. -In the server function, service <-chan *request is a "receive only" channel -that the function can use only to read new requests. -

-We instantiate a server in a familiar way, starting it and returning a channel -connected to it: -

-{{code "progs/server.go" `/func.startServer/` `/^}/`}} -

-The returned channel is send only, even though the channel was created bidirectionally. -The read end is passed to server, while the send end is returned -to the caller of startServer, so the two halves of the channel -are distinguished, just as we did in startServer. -

-Bidirectional channels can be assigned to unidirectional channels but not the -other way around, so if you annotate your channel directions when you declare -them, such as in function signatures, the type system can help you set up and -use channels correctly. -Note that it's pointless to make unidirectional channels, since you can't -use them to communicate. Their purpose is served by variables assigned from bidirectional channels -to distinguish the input and output halves. -

-Here's a simple test. It starts a server with an addition operator and sends out -N requests without waiting for the replies. Only after all the requests are sent -does it check the results. -

-{{code "progs/server.go" `/func.main/` `/^}/`}} -

-One annoyance with this program is that it doesn't shut down the server cleanly; when main returns -there are a number of lingering goroutines blocked on communication. To solve this, -we can provide a second, quit channel to the server: -

-{{code "progs/server1.go" `/func.startServer/` `/^}/`}} -

-It passes the quit channel to the server function, which uses it like this: -

-{{code "progs/server1.go" `/func.server/` `/^}/`}} -

-Inside server, the select statement chooses which of the multiple communications -listed by its cases can proceed. If all are blocked, it waits until one can proceed; if -multiple can proceed, it chooses one at random. In this instance, the select allows -the server to honor requests until it receives a quit message, at which point it -returns, terminating its execution. -

-

-All that's left is to strobe the quit channel -at the end of main: -

-{{code "progs/server1.go" `/adder,.quit/`}} -... -{{code "progs/server1.go" `/quit....true/`}} -

-There's a lot more to Go programming and concurrent programming in general but this -quick tour should give you some of the basics. diff --git a/doc/install-source.html b/doc/install-source.html index 5b138d5796..ecb386f597 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -225,8 +225,7 @@ If you see the "hello, world" message then Go is installed correctly.

What's next

-Start by taking A Tour of Go -or reading the Go Tutorial. +Start by taking A Tour of Go.

diff --git a/doc/makehtml b/doc/makehtml index 8a029132f4..f6f601e3be 100755 --- a/doc/makehtml +++ b/doc/makehtml @@ -5,7 +5,7 @@ set -e -TMPL=${1:-go_tutorial.tmpl} # input file +TMPL=${1:-effective_go.tmpl} # input file HTML=$(dirname $TMPL)/$(basename $TMPL .tmpl).html # output file if ! test -w $HTML diff --git a/doc/progs/cat.go b/doc/progs/cat.go deleted file mode 100644 index 79ad015039..0000000000 --- a/doc/progs/cat.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "./file" - "flag" - "fmt" - "os" -) - -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, er) - 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, ew) - os.Exit(1) - } - } - } -} - -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() - } -} diff --git a/doc/progs/cat_rot13.go b/doc/progs/cat_rot13.go deleted file mode 100644 index c8584ed47c..0000000000 --- a/doc/progs/cat_rot13.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "./file" - "flag" - "fmt" - "os" -) - -var rot13Flag = flag.Bool("rot13", false, "rot13 the input") - -func rot13(b byte) byte { - if 'a' <= b && b <= 'z' { - b = 'a' + ((b-'a')+13)%26 - } - if 'A' <= b && b <= 'Z' { - b = 'A' + ((b-'A')+13)%26 - } - return b -} - -type reader interface { - Read(b []byte) (ret int, err error) - String() string -} - -type rotate13 struct { - source reader -} - -func newRotate13(source reader) *rotate13 { - return &rotate13{source} -} - -func (r13 *rotate13) Read(b []byte) (ret int, err error) { - r, e := r13.source.Read(b) - for i := 0; i < r; i++ { - b[i] = rot13(b[i]) - } - return r, e -} - -func (r13 *rotate13) String() string { - return r13.source.String() -} - -// end of rotate13 implementation OMIT - -func cat(r reader) { - const NBUF = 512 - var buf [NBUF]byte - - 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, er) - 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, ew) - os.Exit(1) - } - } - } -} - -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() - } -} diff --git a/doc/progs/echo.go b/doc/progs/echo.go deleted file mode 100644 index 432e808207..0000000000 --- a/doc/progs/echo.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" // command line option parser - "os" -) - -var omitNewline = flag.Bool("n", false, "don't print final newline") - -const ( - Space = " " - Newline = "\n" -) - -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) -} diff --git a/doc/progs/file.go b/doc/progs/file.go deleted file mode 100644 index 75f0f207ac..0000000000 --- a/doc/progs/file.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package file - -import ( - "os" - "syscall" -) - -type File struct { - fd int // file descriptor number - name string // file name at Open time -} - -func newFile(fd int, name string) *File { - if fd < 0 { - return nil - } - return &File{fd, name} -} - -var ( - Stdin = newFile(syscall.Stdin, "/dev/stdin") - Stdout = newFile(syscall.Stdout, "/dev/stdout") - Stderr = newFile(syscall.Stderr, "/dev/stderr") -) - -func OpenFile(name string, mode int, perm uint32) (file *File, err error) { - r, err := syscall.Open(name, mode, perm) - return newFile(r, name), err -} - -const ( - O_RDONLY = syscall.O_RDONLY - O_RDWR = syscall.O_RDWR - O_CREATE = syscall.O_CREAT - O_TRUNC = syscall.O_TRUNC -) - -func Open(name string) (file *File, err error) { - return OpenFile(name, O_RDONLY, 0) -} - -func Create(name string) (file *File, err error) { - return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666) -} - -func (file *File) Close() error { - if file == nil { - return os.ErrInvalid - } - err := syscall.Close(file.fd) - file.fd = -1 // so it can't be closed again - return err -} - -func (file *File) Read(b []byte) (ret int, err error) { - if file == nil { - return -1, os.ErrInvalid - } - r, err := syscall.Read(file.fd, b) - return int(r), err -} - -func (file *File) Write(b []byte) (ret int, err error) { - if file == nil { - return -1, os.ErrInvalid - } - r, err := syscall.Write(file.fd, b) - return int(r), err -} - -func (file *File) String() string { - return file.name -} diff --git a/doc/progs/file_windows.go b/doc/progs/file_windows.go deleted file mode 100644 index 8b79ee97de..0000000000 --- a/doc/progs/file_windows.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package file - -import ( - "os" - "syscall" -) - -type File struct { - fd syscall.Handle // file descriptor number - name string // file name at Open time -} - -func newFile(fd syscall.Handle, name string) *File { - if fd == ^syscall.Handle(0) { - return nil - } - return &File{fd, name} -} - -var ( - Stdin = newFile(syscall.Stdin, "/dev/stdin") - Stdout = newFile(syscall.Stdout, "/dev/stdout") - Stderr = newFile(syscall.Stderr, "/dev/stderr") -) - -func OpenFile(name string, mode int, perm uint32) (file *File, err error) { - r, err := syscall.Open(name, mode, perm) - return newFile(r, name), err -} - -const ( - O_RDONLY = syscall.O_RDONLY - O_RDWR = syscall.O_RDWR - O_CREATE = syscall.O_CREAT - O_TRUNC = syscall.O_TRUNC -) - -func Open(name string) (file *File, err error) { - return OpenFile(name, O_RDONLY, 0) -} - -func Create(name string) (file *File, err error) { - return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666) -} - -func (file *File) Close() error { - if file == nil { - return os.ErrInvalid - } - err := syscall.Close(file.fd) - file.fd = syscall.InvalidHandle // so it can't be closed again - return err -} - -func (file *File) Read(b []byte) (ret int, err error) { - if file == nil { - return -1, os.ErrInvalid - } - r, err := syscall.Read(file.fd, b) - return int(r), err -} - -func (file *File) Write(b []byte) (ret int, err error) { - if file == nil { - return -1, os.ErrInvalid - } - r, err := syscall.Write(file.fd, b) - return int(r), err -} - -func (file *File) String() string { - return file.name -} diff --git a/doc/progs/run b/doc/progs/run index 5a2b786516..2470d5e8e0 100755 --- a/doc/progs/run +++ b/doc/progs/run @@ -14,12 +14,6 @@ fi rm -f *.$O -if [ "$GOOS" = "windows" ];then - $GC -o file.$O file_windows.go -else - $GC file.go -fi - defer_panic_recover=" defer.go defer2.go @@ -38,29 +32,10 @@ error_handling=" error4.go " -go_tutorial=" - cat.go - cat_rot13.go - echo.go - helloworld.go - helloworld3.go - print.go - print_string.go - server.go - server1.go - sieve.go - sieve1.go - sort.go - sortmain.go - strings.go - sum.go -" - for i in \ $defer_panic_recover \ $effective_go \ $error_handling \ - $go_tutorial \ slices.go \ go1.go \ ; do @@ -80,43 +55,10 @@ function testit { fi } -function testitpipe { - $LD $1.$O - ./$O.out | $2 2>&1 >"$TMPFILE" || true - x=$(echo $(cat "$TMPFILE")) # extra echo canonicalizes - if [ "$x" != "$3" ] - then - echo $1 failed: '"'$x'"' is not '"'$3'"' - fi -} - -testit helloworld "" "Hello, world; or Καλημέρα κόσμε; or こんにちは 世界" -testit helloworld3 "" "hello, world can't open file; err=no such file or directory" -testit echo "hello, world" "hello, world" -testit sum "" "6" -testit strings "" "" testit defer "" "0 3210 2" testit defer2 "" "Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f." -alphabet=abcdefghijklmnopqrstuvwxyz -rot13=nopqrstuvwxyzabcdefghijklm -echo $alphabet | testit cat "" $alphabet -echo $alphabet | testit cat_rot13 "--rot13" $rot13 -echo $rot13 | testit cat_rot13 "--rot13" $alphabet - -testit sortmain "" "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" - -testit print "" "18446744073709551615 -1 18446744073709551615 {77 Sunset Strip} [1 2 3 4] 18446744073709551615 {77 Sunset Strip} [1 2 3 4] 18446744073709551615 {77 Sunset Strip} [1 2 3 4]" -testit print_string "" "77 Sunset Strip" - -testitpipe sieve "sed 10q" "2 3 5 7 11 13 17 19 23 29" -testitpipe sieve "sed 10q" "2 3 5 7 11 13 17 19 23 29" - -# server hangs; don't run it, just compile it -$GC server.go -testit server1 "" "" - testit eff_bytesize "" "1.00YB 9.09TB" testit eff_sequence "" "[-1 2 6 16 44]" diff --git a/doc/progs/sieve.go b/doc/progs/sieve.go deleted file mode 100644 index b315309819..0000000000 --- a/doc/progs/sieve.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "fmt" - -// 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'. - } -} - -// 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'. - } - } -} - -// The prime sieve: Daisy-chain filter processes together. -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 - } -} diff --git a/doc/progs/sieve1.go b/doc/progs/sieve1.go deleted file mode 100644 index e1411a3346..0000000000 --- a/doc/progs/sieve1.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "fmt" - -// Send the sequence 2, 3, 4, ... to returned channel -func generate() chan int { - ch := make(chan int) - go func() { - for i := 2; ; i++ { - ch <- i - } - }() - return ch -} - -// Filter out input values divisible by 'prime', send rest to returned channel -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 -} - -func sieve() chan int { - out := make(chan int) - go func() { - ch := generate() - for { - prime := <-ch - out <- prime - ch = filter(ch, prime) - } - }() - return out -} - -func main() { - primes := sieve() - for i := 0; i < 100; i++ { // Print the first hundred primes. - fmt.Println(<-primes) - } -} diff --git a/doc/progs/sortmain.go b/doc/progs/sortmain.go deleted file mode 100644 index 1bc3355fd0..0000000000 --- a/doc/progs/sortmain.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "./sort" - "fmt" -) - -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") - } -} - -func strings() { - data := []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"} - a := sort.StringSlice(data) - sort.Sort(a) - if !sort.IsSorted(a) { - panic("fail") - } -} - -type day struct { - num int - shortName string - longName string -} - -type dayArray struct { - data []*day -} - -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] } - -func days() { - Sunday := day{0, "SUN", "Sunday"} - Monday := day{1, "MON", "Monday"} - Tuesday := day{2, "TUE", "Tuesday"} - Wednesday := day{3, "WED", "Wednesday"} - Thursday := day{4, "THU", "Thursday"} - Friday := day{5, "FRI", "Friday"} - Saturday := day{6, "SAT", "Saturday"} - data := []*day{&Tuesday, &Thursday, &Wednesday, &Sunday, &Monday, &Friday, &Saturday} - a := dayArray{data} - sort.Sort(&a) - if !sort.IsSorted(&a) { - panic("fail") - } - for _, d := range data { - fmt.Printf("%s ", d.longName) - } - fmt.Printf("\n") -} - -func main() { - ints() - strings() - days() -} diff --git a/doc/talks/go_talk-20100323.html b/doc/talks/go_talk-20100323.html index 3143b079ae..7330dd2ae5 100644 --- a/doc/talks/go_talk-20100323.html +++ b/doc/talks/go_talk-20100323.html @@ -380,7 +380,7 @@ containing other data structures as continuous blocks of memory."

And more:

diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go index 8d592200e9..e5717f8005 100644 --- a/src/cmd/godoc/main.go +++ b/src/cmd/godoc/main.go @@ -7,7 +7,7 @@ // Web server tree: // // http://godoc/ main landing page -// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, tutorial, etc. +// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, etc. // http://godoc/src/ serve files from $GOROOT/src; .go gets pretty-printed // http://godoc/cmd/ serve documentation about commands // http://godoc/pkg/ serve documentation about packages -- 2.48.1