diff --git a/tour/static/index.html b/tour/static/index.html index 016ba622..e0fe44ee 100644 --- a/tour/static/index.html +++ b/tour/static/index.html @@ -1397,15 +1397,6 @@ func main() { -
-

Exercise: Images

-

- Let's eliminate some more scaffolding. -

-
-
- -
Concurrency
@@ -1415,14 +1406,18 @@ func main() {

Goroutines

-

go f(x, y, z) starts a new goroutine running f(x, - y, z). The evaluation +

+ go f(x, y, z) starts a new goroutine running f(x, + y, z). +

+ The evaluation of f, x, y, and z - happens in the current goroutine. After they are evaluated, a new goroutine - is created and it calls f with those arguments. + happens in the current goroutine and the execution of f + happens in the new goroutine. -

Goroutines share memory, so access to shared memory must be - synchronized. The sync package provides useful primitives. +

Goroutines share memory, so access to shared memory must be + synchronized. The sync package provides useful primitives.

package main @@ -1448,39 +1443,36 @@ func main() {

Channels

-

-Channels are typed message buffers with send and receive. - -

Like maps and slices, channels must be created before use: +

+ Channels are a typed conduit through which you can send and receive values with the channel operator, <-.

-ch := make(chan int, 100)
+ch <- v    // send v to channel ch
+v := <-ch  // receive from ch, assign value to v
+
+

+ (The data flows in the direction of the "arrow".) + +

+ Like maps and slices, channels must be created before use: +

+ch := make(chan int)
 
-

This channel has room for 100 ints in its buffer. Sends block when the -buffer is full. Receives block when there's nothing available. This allows -goroutines to synchronize without explicit locks or condition variables. - -

If the second arg to make is omitted or zero, the channel is - unbuffered. Sends to an unbuffered channel block until another goroutine - receives from that channel, and receives block until a value is sent. - -

The built-in function cap(ch) returns the size -of ch's buffer; len(ch) returns the number of elements -in the buffer ready to be received. - +

+ Sends and receives block until the other side is ready. This allows + goroutines to synchronize without explicit locks or condition + variables.

package main -import ( - "fmt" -) +import "fmt" func sum(a []int, c chan int) { - res := 0 + sum := 0 for _, v := range a { - res += v + sum += v } - c <- res + c <- sum // send sum to c } func main() { @@ -1489,7 +1481,7 @@ func main() { c := make(chan int) go sum(a[:len(a)/2], c) go sum(a[len(a)/2:], c) - x, y := <-c, <-c + x, y := <-c, <-c // receive from c fmt.Println(x, y, x + y) } @@ -1497,6 +1489,38 @@ func main() {
+
+

Buffered Channels

+ +

+ Channels can be buffered. Provide the buffer length as the + second argument to make to initialize a buffered channel: +

+ch := make(chan int, 100)
+
+ +

+ Sends to a buffered channel only block when the buffer is full. + Receives block when the buffer is empty. + +

+ Modify the example to overfill the buffer and see what happens. + +

+package main + +import "fmt" + +func main() { + c := make(chan int, 2) + c <- 1 + c <- 2 + fmt.Println(<-c) + fmt.Println(<-c) +} +
+
+

Range and Close

@@ -1617,95 +1641,98 @@ func main() {
-

Exercise: Web Crawler

+

Exercise: Equivalent Binary Trees

+ There can be many different binary trees with the same sequence of + values stored at the leaves. + For example, here are two binary trees storing the sequence + 1, 1, 2, 3, 5, 8, 13. + +

+ A function to check whether two binary trees store the same sequence is + quite complex in most languages. We'll use Go's concurrency and + channels to write a simple solution. +

+ This example uses the tree package, which defines the type: +

+type Tree struct {
+	Left  *Tree
+	Value int
+	Right *Tree
+}
+
+
+ +
+

Exercise: Equivalent Binary Trees

+

+ 1. Implement the Walk function. +

+ 2. Test the Walk function. +

+ The function tree.New(k) constructs a randomly-structured + binary tree holding the values k, 2k, 3k, ..., + 10k. +

+ Create a new channel ch and kick off the walker: +

+go Walk(tree.New(1), ch)
+
+

+ Then read and print 10 values from the channel. + It should be the numbers 1, 2, 3, ..., 10. +

+ 3. Implement the Same function using Walk + to determine whether t1 and t2 store the same values. +

+ 4. Test the Same function. +

+ Same(tree.New(1), tree.New(2)) should return true, and + Same(tree.New(1), tree.New(2)) should return false. -

Change Crawl to run each call to fetcher.Fetch in -its own goroutine and avoid fetching the same URL twice.

package main -import ( - "os" - "fmt" -) +import "go-tour.googlecode.com/hg/tree" -type Fetcher interface { - // Fetch returns the contents of url and a slice - // of URLs on that page that may be crawled. - // It returns an error if url was not found or the fetch failed. - Fetch(url string) (contents string, urls []string, err os.Error) -} +// Walk walks the tree t sending all values +// from the tree to the channel ch. +func Walk(t *tree.Tree, ch chan int) -// Crawl fetches pages recursively starting from url to depth using fetcher. -func Crawl(url string, depth int, fetcher Fetcher) { - // TODO(you): Run each call to fetcher.Fetch in its own goroutine. - // TODO(you): Don't fetch the same URL twice. - // This implementation doesn't do either: - if depth <= 0 { - return - } - contents, urls, err := fetcher.Fetch(url) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(contents) - for _, u := range urls { - Crawl(u, depth-1, fetcher) - } - return -} - -// Fake web of URLs for testing. -type fakeResult struct { - contents string - urls []string -} - -type fakeFetcher map[string]*fakeResult - -func (f *fakeFetcher) Fetch(url string) (contents string, urls []string, err os.Error) { - if res, ok := (*f)[url]; ok { - return res.contents, res.urls, nil - } - return "", nil, fmt.Errorf("not found: %s", url) -} +// Same determines whether the trees +// t1 and t2 contain the same values. +func Same(t1, t2 *tree.Tree) bool func main() { - fetcher := &fakeFetcher{ - "http://golang.org": &fakeResult{ - "The Go Programming Language", - []string{ - "http://golang.org/pkg", - "http://golang.org/cmd", - }, - }, - "http://golang.org/pkg": &fakeResult{ - "Packages", - []string{ - "http://golang.org", - "http://golang.org/cmd", - "http://golang.org/pkg/fmt", - "http://golang.org/pkg/os", - }, - }, - "http://golang.org/pkg/fmt": &fakeResult{ - "Package fmt", - []string{}, - }, - "http://golang.org/pkg/os": &fakeResult{ - "Package os", - []string{}, - }, - } - Crawl("http://golang.org", 3, fetcher) }
-
-

More here...

+
+

Where to Go from here...

+

+ The Go Documentation is + a great place to start. It contains references, tutorials, videos, and more. +

+ If you need help with the standard library, + see the package reference. + For help with the language itself, you might be surprised to find the + Language Spec is quite readable. +

+ If you're interested in writing web applications, + see the Wiki Codelab. +

+ If you want to further explore Go's concurrency model, see the + Share Memory by Communicating + codewalk. +

+ The First Class Functions in Go + codewalk gives an interesting perspective on Go's function types. +

+ The Go Blog has a large archive of + informative Go articles. +

+ Visit golang.org for more.