LoginSignup
9
3

More than 5 years have passed since last update.

A Tour of Goをやり終えた

Last updated at Posted at 2016-12-23

約1ヶ月かけてGoのチュートリアルA Tour of Goをひと通りやり終えた。実行環境はそのままサイト内のplaygroundのみを使った。

参考にしたもの

  • How to Write Go Code
  • WEB+DB PRESS vol.82 はじめてのGo
  • WEB+DB PRESS vol.95 Goによる並行処理

以下、各課題で書いたコードとメモ。

2016/11/13 Start

記念すべきGo学習を始めた日。Packages

2016/11/23 課題:Forループ/ニュートン法

ニュートン法を扱う課題。なにこの数式、いきなりやばい。と思いながら、なんとか正しい出力結果を得たものの、forループの課題なのにforループ使わず再帰処理で無理やりグローバル変数とか使ってたりして、出題者の意図をくみ取れず。。。

package main

import (
     "fmt"
     "math"
)

var z = 1.0
var cnt = 0

func Sqrt(x float64) float64 {
     zbuf := z
     z = z - (z*z-x)/(2*z)
     fmt.Println(cnt, z)
     if math.Abs(zbuf-z) < 0.000001 {
          return z
     }
     cnt++
     return Sqrt(x)
}

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

出力結果

0 2
1 1.75
2 1.7321428571428572
3 1.7320508100147276
4 1.7320508075688772
1.7320508075688772
1.7320508075688772

2016/11/26 課題:スライス

Exercise:Slices
これも、むずかしかったが、ごにょごにょしてたらできた。綺麗な画像が出てきたときは感動。

package main

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

func Pic(dx, dy int) [][]uint8 {
     pic := make([][]uint8, dy)
     for y := 0; y < dy; y++ {
          pic[y] = make([]uint8, dx)
          for x := 0; x < dx; x++ {
               pic[y][x] = uint8((x+y)/2)
          }

     }
     return pic
}

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

出力結果
Slice.png

2016/11/26 課題:マップ

Exercise: Maps
マップの課題。APIリファレンスを見ながら書いた。なんとかできた。が、コードを見返すとなにをやっているか理解できない。

package main

import (
    "strings"
    "fmt"
    "golang.org/x/tour/wc"
)

func WordCount(s string) map[string]int {
    sf := strings.Fields(s)
    fmt.Println(sf)

    smap := make(map[string]int)
    for _, elm := range sf {
        fmt.Println(elm)
        smap[elm] = smap[elm] + 1
    }
    return smap
}

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

出力結果

[I am learning Go!]
I
am
learning
Go!
PASS
 f("I am learning Go!") = 
  map[string]int{"I":1, "am":1, "learning":1, "Go!":1}
[The quick brown fox jumped over the lazy dog.]
The
quick
brown
fox
jumped
over
the
lazy
dog.
PASS
 f("The quick brown fox jumped over the lazy dog.") = 
  map[string]int{"jumped":1, "the":1, "The":1, "quick":1, "brown":1, "fox":1, "over":1, "lazy":1, "dog.":1}
[I ate a donut. Then I ate another donut.]
I
ate
a
donut.
Then
I
ate
another
donut.
PASS
 f("I ate a donut. Then I ate another donut.") = 
  map[string]int{"another":1, "I":2, "ate":2, "a":1, "donut.":2, "Then":1}
[A man a plan a canal panama.]
A
man
a
plan
a
canal
panama.
PASS
 f("A man a plan a canal panama.") = 
  map[string]int{"man":1, "a":2, "plan":1, "canal":1, "panama.":1, "A":1}

2016/11/27 課題:クロージャ/フィボナッチ数列

Exercise: Fibonacci closure
これはすごく苦労した記憶があるが、なんかできた。今、コードを見返してみてもよくわからない(汗)

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
     var f []int
     return func() int {
          switch len(f) {
          case 0:
               f = append(f, 0)
          case 1:
               f = append(f, 1)
          default:
               f = append(f, (f[len(f)-2] + f[len(f)-1]))
          }
          return f[len(f)-1]
     }
}

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

出力結果

0
1
1
2
3
5
8
13
21
34

2016/12/11 課題:エラー

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) {
    var err ErrNegativeSqrt
    if x < 0 {
        err = ErrNegativeSqrt(x)
        return 0, err
    }

    last_z, z := x, 1.0
    for math.Abs(z-last_z) >= 1.0e-6 {
        last_z, z = z, z-(z*z-x)/(2*z)
    }
    return z, nil
}

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

出力結果

1.4142135623730951 <nil>
0 cannot Sqrt negative number: -2

2016/12/11 課題:Reader

Exercise: Readers
ASCII文字 'A' の無限ストリームを出力する Reader 型を実装してください。というよくわからん課題。あまり覚えてないが、なんかできた。

package main

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

type MyReader struct{}

// TODO: Add a Read([]byte) (int, error) method to MyReader.
func (r MyReader) Read(b []byte) (int, error) {
    for {
        copy(b,"A")
        return 1, nil
    }
}

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

出力結果

OK!

2016/12/11 課題:Readerをラップする/rot13Reader

これはギブアップ。できませんでした。
Exercise: rot13Reader

2016/12/14 課題:Imageインターフェイス

Exercise: Images
よく覚えてないが、APIリファレンスの見よう見まねで書いたらできた。

package main

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

type Image struct{}

// ColorModel returns the Image's color model.
func (img Image) ColorModel() color.Model {
    return color.RGBAModel
}

// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
func (img Image) Bounds() image.Rectangle {
    return image.Rect(0, 0, 100, 100)
}

// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
func (img Image) At(x, y int) color.Color {
    return color.RGBA{0, 0, 255, 255}
}
func main() {
    m := Image{}
    pic.ShowImage(m)
}

出力結果
ImageInterface.png

2016/12/20 課題:並行処理/2分木

いよいよGoの本丸といえる並行処理についての課題。この課題、3日ぐらいかけて相当ねばったが、結局ギブアップ。かなり解まで近づいて、めちゃくちゃ悔しかったので別記事で詳細を書いている。
3日かけてA Tour of Goの練習問題に挑戦して結局解けなかった話

2016/12/23 最後の課題:並行処理/Webクローラ

簡単ではなかったが、雑誌の記事や、チュートリアルを参考にすればできた。

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) {
    c := SafeCounter{v: make(map[string]int)}
    ch := make(chan string)
    go InnerCrawl(url, depth, fetcher, ch , &c)
    fmt.Println("<-ch", <-ch)
    return
}

func InnerCrawl(url string, depth int, fetcher Fetcher, ch chan string, c *SafeCounter) {
    c.Inc(url)
    cnt := c.Value(url)
    if cnt > 1 {
        fmt.Printf("duplicate cnt:%v url:%s\n",cnt, url)
        ch <- url
        return
    }

    fmt.Println("depth:",depth)
    if depth <= 0 {
        ch <- url
        return
    }

    body, urls, err := fetcher.Fetch(url)
    if err != nil {
        fmt.Println(err)
        ch <- url
        return
    }

    fmt.Printf("found: %s %q\n", url, body)

    fmt.Printf("len(urls):%v\n", len(urls))
    ich := make(chan string)
    for _, u := range urls {
        go InnerCrawl(u, depth-1, fetcher, ich, c)
    }

    for i := 0; i < len(urls); i++ {
        fmt.Println("<-ich", <-ich)
    }

    ch <- url
    return
}

func main() {
    Crawl("http://golang.org/", 4, fetcher)
}

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

// SafeCounter is safe to use concurrently.
type SafeCounter struct {
    v   map[string]int
    mux sync.Mutex
}

// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
    c.mux.Lock()
    // Lock so only one goroutine at a time can access the map c.v.
    c.v[key]++
    c.mux.Unlock()
}

// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
    c.mux.Lock()
    // Lock so only one goroutine at a time can access the map c.v.
    defer c.mux.Unlock()
    return c.v[key]
}

出力結果

found: http://golang.org/ "The Go Programming Language"
not found: http://golang.org/cmd/
<-ich http://golang.org/cmd/
found: http://golang.org/pkg/ "Packages"
found: http://golang.org/pkg/os/ "Package os"
duplicate cnt:2 url:http://golang.org/pkg/
<-ich http://golang.org/pkg/
duplicate cnt:2 url:http://golang.org/
<-ich http://golang.org/
duplicate cnt:2 url:http://golang.org/cmd/
<-ich http://golang.org/cmd/
found: http://golang.org/pkg/fmt/ "Package fmt"
duplicate cnt:3 url:http://golang.org/pkg/
<-ich http://golang.org/pkg/
duplicate cnt:3 url:http://golang.org/
<-ich http://golang.org/
<-ich http://golang.org/pkg/os/
duplicate cnt:4 url:http://golang.org/
<-ich http://golang.org/
<-ich http://golang.org/pkg/fmt/
<-ich http://golang.org/pkg/
<-ch http://golang.org/

まとめ

これで終わり。変なコード書いていたら、ご指摘お願いします。
playgroundはコードが保存されて便利だが、この記事を書くにあたって過去のコードを見返してみると全然記憶がなかったりするので総括としては

コメントは残しておこう。

です。
以上、現場からでした。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3