LoginSignup
1
0

More than 3 years have passed since last update.

A Tour of Go メモ ~Methods and interfaces~

Posted at

はじめに

Go の勉強のため、A Tour of Goに取り組んでいる
今回はMethods and interfaces章について、学んだことを記していく

まとめ記事はこちら

使えそうなスニペット

※筆者は VSCode を使用

meth

method を作成する。すごい便利

func (receiver type) method()  {

}

tyi

type name interface {

}

ページごとの補足

Methods and pointer indirection

struct と*struct の違いを調べておきたい

The empty interface

使いみち

Typescript におけるunknownに近い?

Type assertions

使いみち

var i interface{} = "Hello"
s, ok := i.(int) // no panic
var i interface{} = "Hello"
s := i.(int) // panic

Exercise: Stringers

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

マジックナンバーを使わない場合、こんな感じになりそう

func (ip IPAddr) String() string {
    stringArray := make([]string, 0, len(ip))
    for _, i := range ip {
        stringArray = append(stringArray, fmt.Sprint(i))
    }
    return strings.Join(stringArray, ".")
}

Errors

関数の返り値の型にerrorを指定した場合、return した値のError()メソッドが実行される

Exercise: Errors

naked return ステートメントが便利
error の初期値に nil が勝手に入ってくれる

type ErrNegativeSqrt float64

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

func Sqrt(x float64) (z float64, e error) {
    if x < 0 {
        e = ErrNegativeSqrt(x)
        return
    }
    z = 1
    for i := 0; i < 10; i++ {
        z -= (z*z - x) / (2 * z)
    }
    return
}

func main() {
    fmt.Println(Sqrt(2))  // 1.414213562373095 <nil>
    fmt.Println(Sqrt(-2)) // 0 Error: -2

}

Exercise: Readers

一応バリデーションは通ったが、こんな実装で良いか不明
他の人の回答を見ると、strings.NewReaderを使わずにシンプルに byte スライスにAを挿入していた
それでいいのか……

type MyReader struct{}

func (m MyReader) Error() string {
    return fmt.Sprint("Error!")
}

func (m MyReader) Read(b []byte) (int, error) {
    var a string
    for i := 0; i < len(b); i++ {
        a += "A"
    }
    r := strings.NewReader(a)

    for {
        _, err := r.Read(b)
        if err == io.EOF {
            break
        }
    }
    return len(b), nil
}

Exercise: rot13Reader

実装自体は単純
ただ、変換後の文字列をどう返せばいいのか悩んだ
Readの引数に渡ってくる byte に文字を格納することで、その文字列が返る

また、13 を足すか引くかを元々数字で判断していた(b < 65のように)
しかし、runeを使うことで、直感的に書くことができる
※ただし、これができるのは一部の文字だけ。日本語は NG

func rot(b byte) byte {
    const ROT = 13
    switch {
    case b < 'A':
        return b
    case b < 'N':
        return b + ROT
    case b < 'a':
        return b - ROT
    case b < 'n':
        return b + ROT
    case b <= 'z':
        return b - ROT
    default:
        return b
    }
}

func (r *rot13Reader) Read(b []byte) (n int, err error) {
    n, err = r.r.Read(b)
    if err != io.EOF {
        for i := range b {
            b[i] = rot(b[i])
        }
    }
    return n, err
}

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

Exercise: Images

struct 初期化時に表示計算用の関数fnを与えるようにしてみた

package main

import (
    "fmt"
    "image"
    "image/color"

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

type MyImage struct {
    x0, y0, x1, y1 int
    fn             func(x, y int) int
}

func (m MyImage) At(x, y int) color.Color {
    v := uint8(m.fn(x, y))
    return color.RGBA{v, v, 255, 255}
}
func (m MyImage) Bounds() image.Rectangle {
    return image.Rect(m.x0, m.y0, m.x1, m.y1)
}
func (m MyImage) ColorModel() color.Model {
    return color.RGBAModel
}

func main() {
    fn := func(x, y int) int { return x - y }
    m := MyImage{0, 0, 100, 100, fn}
    fmt.Println(m.Bounds())
    fmt.Println(m.At(0, 0).RGBA())
    pic.ShowImage(m)
}
1
0
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
1
0