Goをやることになったので、とりあえずA Tour of Goをやって、演習問題を解いてみた。直近ではgoroutineは使わなそうだったので、ひとまずそれ以外の演習問題をした。
回答は https://github.com/shibayu36/golang-playground/tree/master/go-tour に置いている。
Exercise: Loops and Functions
for文の使い方を学べる。for文の初期化ステートメントと条件式を使えば解ける。
package main import ( "fmt" "math" ) func Sqrt(x float64) float64 { z := 1.0 for diff := 1.0; math.Abs(diff) > 1e-10; { diff = ((z * z) - x) / (2 * z) z = z - diff } return z } func main() { fmt.Println(Sqrt(3)) fmt.Println(math.Sqrt(3)) }
Exercise: Slices
- rangeをうまく使うと綺麗にかけた
- 多次元配列だと、ループでmakeしなければならない
- uint8()でキャストしないといけない
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) } } return pic } func main() { pic.Show(Pic) }
Exercise: Maps
- string.Fieldsを使ってワード分割
- mapの値を増やしていくだけで良い
package main import ( "strings" "golang.org/x/tour/wc" ) func WordCount(s string) map[string]int { words := strings.Fields(s) wordToCount := make(map[string]int) for _, word := range words { wordToCount[word]++ } return wordToCount } func main() { wc.Test(WordCount) }
Exercise: Fibonacci closure
クロージャで変数を二つ持っておくと綺麗に書ける。
package main import "fmt" func fibonacci() func() int { a1, a2 := 0, 1 return func() int { ret := a1 a1, a2 = a2, a1 + a2 return ret } } func main() { f := fibonacci() for i := 0; i < 10; i++ { fmt.Println(f()) } }
Exercise: Stringers
typeにメソッドを生やす練習
package main import "fmt" type IPAddr [4]byte func (ipAddr IPAddr) String() string { return fmt.Sprintf("%d.%d.%d.%d", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]) } func main() { hosts := map[string]IPAddr{ "loopback": {127, 0, 0, 1}, "googleDNS": {8, 8, 8, 8}, } for name, ip := range hosts { fmt.Printf("%v: %v\n", name, ip) } }
Exercise: Errors
Errorメソッドを生やすだけで簡単に独自エラーを定義できる。
package main import ( "fmt" "math" ) type ErrNegativeSqrt float64 func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("cannot Sqrt negative number: %f", e) } func Sqrt(x float64) (float64, error) { if x < 0 { return 0, ErrNegativeSqrt(x) } z := 1.0 for diff := 1.0; math.Abs(diff) > 1e-10; { diff = ((z * z) - x) / (2 * z) z = z - diff } 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(buf []byte) (int, error) { for i := range buf { buf[i] = 'A' } return len(buf), nil } func main() { reader.Validate(MyReader{}) }
Exercise: rot13Reader
非公開メソッドで変換を書きつつ、Readを実装。
package main import ( "io" "os" "strings" ) type rot13Reader struct { r io.Reader } func (reader *rot13Reader) Read(buf []byte) (int, error) { n, err := reader.r.Read(buf) if err != nil { return 0, err } for i := 0; i < n; i++ { buf[i] = reader.rot13(buf[i]) } return n, nil } func (reader *rot13Reader) rot13(b byte) (byte) { if ('a' <= b && b <= 'm') || ('A' <= b && b <= 'M') { return b + 13 } if ('n' <= b && b <= 'z') || ('N' <= b && b <= 'Z') { return b - 13 } return b } func main() { s := strings.NewReader("Lbh penpxrq gur pbqr!") r := rot13Reader{s} io.Copy(os.Stdout, &r) }
Exercise: Images
自分でImage typeを定義しつつ、インターフェース仕様を満たすように実装。
package main import ( "image" "image/color" "golang.org/x/tour/pic" ) type Image struct { width int height int } func (i Image) ColorModel() color.Model { return color.RGBAModel } func (i Image) Bounds() image.Rectangle { return image.Rect(0, 0, i.width, i.height) } func (i Image) At(x, y int) color.Color { v := uint8((x + y) / 2) return color.RGBA{v, v, 255, 255} } func main() { m := Image{256, 256} pic.ShowImage(m) }