A Tour of Goをやり終えた


約１ヶ月かけてGoのチュートリアル[A Tour of Go](https://go-tour-jp.appspot.com/)をひと通りやり終えた。実行環境はそのままサイト内のplaygroundのみを使った。

### 参考にしたもの

* [How to Write Go Code](https://golang.org/doc/code.html)
- WEB+DB PRESS vol.82 はじめてのGo
- WEB+DB PRESS vol.95 Goによる並行処理

以下、各課題で書いたコードとメモ。
## 2016/11/13 Start
記念すべきGo学習を始めた日。[Packages](https://go-tour-jp.appspot.com/basics/1)

## 2016/11/23 課題：Forループ/ニュートン法
[ニュートン法](https://go-tour-jp.appspot.com/flowcontrol/8)を扱う課題。なにこの数式、いきなりやばい。と思いながら、なんとか正しい出力結果を得たものの、forループの課題なのにforループ使わず再帰処理で無理やりグローバル変数とか使ってたりして、出題者の意図をくみ取れず。。。

```Go
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](https://go-tour-jp.appspot.com/moretypes/18)
これも、むずかしかったが、ごにょごにょしてたらできた。綺麗な画像が出てきたときは感動。

```Go
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](https://qiita-image-store.s3.amazonaws.com/0/49022/aa3d481a-bab8-868d-55d1-4ae235294d2b.png "Slice.png")

## 2016/11/26 課題：マップ
[Exercise: Maps](https://go-tour-jp.appspot.com/moretypes/23)
マップの課題。APIリファレンスを見ながら書いた。なんとかできた。が、コードを見返すとなにをやっているか理解できない。

```Go
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](https://go-tour-jp.appspot.com/moretypes/26)
これはすごく苦労した記憶があるが、なんかできた。今、コードを見返してみてもよくわからない（汗）

```Go
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](https://go-tour-jp.appspot.com/methods/20)
あまり覚えてない。一応、できてると思います。

```Go
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](https://go-tour-jp.appspot.com/methods/22)
ASCII文字 'A' の無限ストリームを出力する Reader 型を実装してください。というよくわからん課題。あまり覚えてないが、なんかできた。

```Go
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](https://go-tour-jp.appspot.com/methods/23)

## 2016/12/14 課題：Imageインターフェイス
[Exercise: Images](https://go-tour-jp.appspot.com/methods/25)
よく覚えてないが、APIリファレンスの見よう見まねで書いたらできた。

```Go
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](https://qiita-image-store.s3.amazonaws.com/0/49022/630b8a8c-bb1f-2c17-e1d1-8db66414ed80.png "ImageInterface.png")


## 2016/12/20 課題：並行処理/2分木
いよいよGoの本丸といえる並行処理についての課題。この課題、３日ぐらいかけて相当ねばったが、結局ギブアップ。かなり解まで近づいて、めちゃくちゃ悔しかったので別記事で詳細を書いている。
[3日かけてA Tour of Goの練習問題に挑戦して結局解けなかった話](http://qiita.com/dondoko-susumu/items/a0a2cdd5bb97c075148c)

## 2016/12/23 最後の課題：並行処理/Webクローラ
簡単ではなかったが、雑誌の記事や、チュートリアルを参考にすればできた。

```Go
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はコードが保存されて便利だが、この記事を書くにあたって過去のコードを見返してみると全然記憶がなかったりするので総括としては

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

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