go-tour对于想学习golang的人来说是一个很好的教程。
首先go-tour是有web版本,但是需要FQ。如果不能FQ的,也可以在google code上自己下载go-tour源码,go build,run一下,在自己的机器上就可以跑这个教程了。
提醒下,如果是后者,这篇文章中的程序对应的import包就需要进行相应修改了。
下面给出我的go-tour中的Exercise的解答(在web上已经测试通过)
Exercise: Loops and Functions
第一个循环10次:
package main import ( "fmt" ) func Sqrt(x float64) float64 { z := float64(1) for i := 0; i <= 10; i++ { z = z - (z*z - x) / (2 * z) } return z } func main() { fmt.Println(Sqrt(2)) }
第二次无限接近:
package main import ( "fmt" "math" ) func Sqrt(x float64) float64 { z := float64(1) for { y := z - (z*z - x) / (2 * z) if math.Abs(y - z) < 1e-10 { return y } z = y; } return z } func main() { fmt.Println(Sqrt(2)) fmt.Println(math.Sqrt(2)) }
Exercise: Maps
package main import ( "tour/wc" "strings" ) func WordCount(s string) map[string]int { ret := make(map[string]int) arr := strings.Fields(s) for _, val := range arr { ret[val]++ } return ret } func main() { wc.Test(WordCount) }
Exercise: Slices
package main import "tour/pic" func Pic(dx, dy int) [][]uint8 { ret := make([][]uint8, dy) for i:=0; i<dy; i++ { ret[i] = make([]uint8, dx) for j:=0; j<dx; j++ { ret[i][j] = uint8(i*j) } } return ret } func main() { pic.Show(Pic) }
Exercise: Fibonacci closure
package main import "fmt" // fibonacci is a function that returns // a function that returns an int. func fibonacci() func() int { sum1 := 0 sum2 := 1 return func() int{ out := sum1 + sum2 sum1 = sum2 sum2 = out return out } } func main() { f := fibonacci() for i := 0; i < 10; i++ { fmt.Println(f()) } }
Advanced Exercise: Complex cube roots
package main import ( "fmt" "math/cmplx" ) func Cbrt(x complex128) complex128 { z := complex128(1) for { if y := z-(cmplx.Pow(z,3) - x)/(3 * z * z); cmplx.Abs(y - z) < 1e-10 { return y } else { z = y } } return z } func main() { fmt.Println(Cbrt(2)) }
Exercise: Errors
package main import ( "fmt" "math" ) type ErrNegativeSqrt float64 func (e ErrNegativeSqrt) Error() string { return "cannot Sqrt negative number:" + fmt.Sprint(float64(e)) } func Sqrt(f float64) (float64, error) { if f < 0 { return 0, ErrNegativeSqrt(f) } z := float64(1) for { y := z - (z*z-f)/(2*z) if math.Abs(y-z) < 1e-10 { return y, nil } z = y } return z, nil } func main() { fmt.Println(Sqrt(2)) fmt.Println(Sqrt(-2)) }
Exercise: Images
package main import ( "image" "tour/pic" "image/color" ) type Image struct{ W int H int } func(self Image) Bounds() image.Rectangle { return image.Rect(0, 0, self.W, self.H) } func(self Image) ColorModel() color.Model { return color.RGBAModel } func(self Image) At(x,y int) color.Color { return color.RGBA{uint8(x), uint8(y), 255, 255} } func main() { m := Image{W:100, H:100} pic.ShowImage(m) }
Exercise: Rot13 Reader
package main import ( "io" "os" "strings" ) type rot13Reader struct { r io.Reader } func(self rot13Reader)Read(p []byte) (n int, err error){ self.r.Read(p) leng := len(p) for i := 0; i < leng; i++ { switch{ case p[i] >= 'a' && p[i] < 'n': fallthrough case p[i] >= 'A' && p[i] < 'N': p[i] = p[i] + 13 case p[i] >= 'n' && p[i] <= 'z': fallthrough case p[i] >= 'N' && p[i] <= 'Z': p[i] = p[i] - 13 } } return leng, nil } func main() { s := strings.NewReader( "Lbh penpxrq gur pbqr!") r := rot13Reader{s} io.Copy(os.Stdout, &r) }
Exercise: Equivalent Binary Trees
package main import ( "tour/tree" ) // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int) { if t == nil { return } Walk(t.Left, ch) ch <- t.Value Walk(t.Right, ch) } // Same determines whether the trees // t1 and t2 contain the same values. func Same(t1, t2 *tree.Tree) bool { ch1 := make(chan int) ch2 := make(chan int) go func() { Walk(t1, ch1) ch1 <- 0 }() go func() { Walk(t2, ch2) ch2 <- 0 }() for { t1 := <-ch1 t2 := <-ch2 if t1 == 0 && t2 == 0 { return true; } if t1 == t2 { continue; } else { return false; } } return true } func main() { ch := make(chan int) go func() { Walk(tree.New(1), ch) ch <- 0 }() for { t := <-ch if t == 0 { break; } println(t) } println(Same(tree.New(1), tree.New(2))) }
Exercise: Web Crawler
package main import ( "fmt" "sync" ) type Fetcher interface { // Fetch returns the body of URL and // a slice of URLs found on that page. Fetch(url string) (body string, urls []string, err error) } // Crawl uses fetcher to recursively crawl // pages starting with url, to a maximum of depth. func Crawl(url string, depth int, fetcher Fetcher, out chan string, end chan bool) { if depth <= 0 { end <- true return } if _, ok := crawled[url]; ok { end <- true return } crawledMutex.Lock() crawled[url] = true crawledMutex.Unlock() body, urls, err := fetcher.Fetch(url) if err != nil { out <- fmt.Sprintln(err) end <- true return } out <- fmt.Sprintf("found: %s %q\n", url, body) subEnd := make(chan bool) for _, u := range urls { go Crawl(u, depth-1, fetcher, out, subEnd) } for i := 0; i < len(urls); i++ { <- subEnd } end <- true } var crawled = make(map[string]bool) var crawledMutex sync.Mutex func main() { out := make(chan string) end := make(chan bool) go Crawl("http://golang.org/", 4, fetcher, out, end) for { select { case t := <- out: fmt.Print(t) case <- end: return } } } // fakeFetcher is Fetcher that returns canned results. type fakeFetcher map[string]*fakeResult type fakeResult struct { body string urls []string } func (f *fakeFetcher) Fetch(url string) (string, []string, error) { if res, ok := (*f)[url]; ok { return res.body, res.urls, nil } return "", nil, fmt.Errorf("not found: %s", url) } // fetcher is a populated fakeFetcher. var 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/", "http://golang.org/pkg/", }, }, "http://golang.org/pkg/os/": &fakeResult{ "Package os", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, }