代码改变世界

go-tour练习解答

2012-12-09 19:15  轩脉刃  阅读(8847)  评论(2编辑  收藏  举报

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/",
          },
     },
}