ITと雑記とド田舎と

ド田舎在住エンジニアがIT備忘録と雑記を書くブログです

A Tour of Go Exerciseの解答まとめ

A Tour of Go Exerciseの解答まとめ

A Tour of Goを終えたのでExerciseの解答を残しておきます。
すべて自力で解答しています。
答え合わせはこちらを参考にさせていただきました。

Exercise: Loops and Functions

package main

import (
    "fmt"
    "math"
)

func Sqrt(x float64) float64 {
    z := 1.0
    for dz := z; math.Abs(dz) > 1e-12; z -= dz {
        dz = (z*z - x) / (2 * z)
        fmt.Println(dz, z)
    }
    return z
}

func main() {
    fmt.Println(Sqrt(10))
    fmt.Println(math.Sqrt(10))
}

Exercise: Slices

package main

import "golang.org/x/tour/pic"

func Pic(dx, dy int) [][]uint8 {
    pic := make([][]uint8, dy)
    for y := range pic {
        pic[y] = make([]uint8, dx)
        for x := range pic[y] {
            //pic[y][x] = uint8((x + y) / 2)
            pic[y][x] = uint8(x * x)
        }
    }
    return pic
}

func main() {
    pic.Show(Pic)
}

Exercise: Maps

package main

import (
    "strings"

    "golang.org/x/tour/wc"
)

func WordCount(s string) map[string]int {
    words := strings.Fields(s)
    result := make(map[string]int)
    for _, word := range words {
        result[word]++
    }
    return result
}

func main() {
    wc.Test(WordCount)
}

Exercise: Fibonacci closure

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
    num1, num2 := 0, 1
    return func() int {
        num := num1
        num1, num2 = num2, num1+num2
        return num
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

Exercise: Stringers

package main

import "fmt"

type IPAddr [4]byte

func (ip IPAddr) String() string {
    return fmt.Sprintf("%v.%v.%v.%v", ip[0], ip[1], ip[2], ip[3])
}

func main() {
    hosts := map[string]IPAddr{
        "loopback":  {127, 0, 0, 1},
        "googleNDS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Printf("%v: %v\n", name, ip)
    }
}

Exercise: Errors

package main

import (
    "fmt"
    "math"
)

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
    return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}

func Sqrt(x float64) (float64, error) {
    if x < 0.0 {
        return x, ErrNegativeSqrt(x)
    }

    z := 1.0
    for dz := z; math.Abs(dz) > 1e-12; z -= dz {
        dz = (z*z - x) / (2 * z)
    }
    return z, nil
}

func main() {
    fmt.Println(Sqrt(2))
    fmt.Println(Sqrt(-2))
}

Exercise: Readers

package main

import "golang.org/x/tour/reader"

type MyReader struct{}

func (r MyReader) Read(b []byte) (int, error) {
    for i := range b {
        b[i] = 'A'
    }
    return len(b), nil
}

func main() {
    reader.Validate(MyReader{})
}

Exercise: rot13Reader

package main

import (
    "io"
    "os"
    "strings"
)

type rot13Reader struct {
    r io.Reader
}

func (rot rot13Reader) Read(b []byte) (int, error) {
    n, err := rot.r.Read(b)
    for i, value := range b {
        diff := value - 'A'

        if (diff >= 0 && diff < 13) || (diff >= 32 && diff < 45) {
            b[i] += 13
        } else {
            b[i] -= 13
        }

    }
    return n, err
}

func main() {
    s := strings.NewReader("Lbh penpxrq gur pbqr!")
    r := rot13Reader{s}
    io.Copy(os.Stdout, &r)
}

Exercise: Images

package main

import (
    "golang.org/x/tour/pic"
    "math/rand"
    "time"
    "image"
    "image/color"
)

type Image struct{}

func (img Image) Bounds() image.Rectangle  {
    return image.Rect(0, 0, 160, 120)
}

func (img Image) ColorModel() color.Model {
    return color.RGBAModel
}

func (img Image) At(x, y int) color.Color {
    return color.RGBA{uint8(rand.Intn(255)), uint8(rand.Intn(255)), 255, 255}
}

func main() {
    rand.Seed(time.Now().UnixNano())
    m := Image{}
    pic.ShowImage(m)
}

Exercise: Equivalent Binary Trees

package main

import (
    "fmt"
    "golang.org/x/tour/tree"
)

func Walk(t *tree.Tree, ch chan int) {
    if t.Left != nil {
        Walk(t.Left, ch)
    }
    ch <- t.Value
    if t.Right != nil {
        Walk(t.Right, ch)
    }
}

func Same(t1, t2 *tree.Tree) bool {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go Walk(t1, ch1)
    go Walk(t2, ch2)
    for i := 0; i < 10; i++ {
        if <-ch1 != <-ch2 {
            return false
        }
    }

    return true
}

func main() {
    ch := make(chan int)
    go Walk(tree.New(1), ch)
    for i := 0; i < 10; i++ {
        fmt.Println(<-ch)
    }

    fmt.Println(Same(tree.New(1), tree.New(1)))
    fmt.Println(Same(tree.New(1), tree.New(2)))
}

Exercise: Web Crawler

package main

import (
    "fmt"
    "sync"
)

type Fetcher interface {
    Fetch(url string) (body string, urls []string, err error)
}

func (fetched *FetchedURLs) Crawl(url string, depth int, fetcher Fetcher) {
    if depth <= 0 {
        fetched.wg.Done()
        return
    }

    fetched.mux.Lock()
    if fetched.urls[url] {
        defer fetched.mux.Unlock()
        fetched.wg.Done()
        return
    }

    body, urls, err := fetcher.Fetch(url)
    if err != nil {
        fmt.Println(err)
        fetched.urls[url] = true
        defer fetched.mux.Unlock()
        fetched.wg.Done()
        return
    }

    fetched.urls[url] = true
    defer fetched.mux.Unlock()
    fmt.Printf("found: %s %q\n", url, body)
    for _, u := range urls {
        fetched.wg.Add(1)
        go fetched.Crawl(u, depth-1, fetcher)
    }
    fetched.wg.Done()
    return
}

func main() {
    fetched := FetchedURLs{urls: make(map[string]bool)}
    fetched.wg.Add(1)
    go fetched.Crawl("https://golang.org/", 4, fetcher)
    fetched.wg.Wait()
}

type fakeFetcher map[string]*fakeResult

type FetchedURLs struct {
    urls map[string]bool
    mux  sync.Mutex
    wg   sync.WaitGroup
}

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

var fetcher = fakeFetcher{
    "https://golang.org/": &fakeResult{
        "The Go Programming Language",
        []string{
            "https://golang.org/pkg/",
            "https://golang.org/cmd/",
        },
    },
    "https://golang.org/pkg/": &fakeResult{
        "Packages",
        []string{
            "https://golang.org/",
            "https://golang.org/cmd/",
            "https://golang.org/pkg/fmt/",
            "https://golang.org/pkg/os/",
        },
    },
    "https://golang.org/pkg/fmt/": &fakeResult{
        "Package fmt",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
    "https://golang.org/pkg/os/": &fakeResult{
        "Package os",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
}

参照