go-tour練習解答

32007 ワード

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

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