週報7/20
Go
メソッド、値レシーバー、ポインタレシーバー
オブジェクト指向でコードを書けることができるのか。
package main import "fmt" type Vertex struct { X, Y int } func (v Vertex) Area() int { return v.X * v.Y } func (v *Vertex) Scale(i int) { v.X = v.X * i v.Y = v.Y * i } func Area(v Vertex) int { return v.X * v.Y } func main() { v := Vertex{3, 4} v.Scale(10) fmt.Println(v.Area()) }
ポインタレシーバーはメモリに書き込むので変数が変化する。
func (v *Vertex) Scale(i int) { v.X = v.X * i v.Y = v.Y * i }
コンストラクタ
Goのひとつのデザインパターン。
Newで数値を代入するのか
package main import "fmt" type Vertex struct { x, y int } func (v Vertex) Area() int { return v.x * v.y } func (v *Vertex) Scale(i int) { v.x = v.x * i v.y = v.y * i } //func Area(v Vertex) int { // return v.x * v.y //} func New(x, y int) *Vertex { return &Vertex{x, y} } func main() { //v := Vertex{3, 4} v := New(3, 4) v.Scale(10) fmt.Println(v.Area()) }
自変数のストラクト
自分で宣言した変数でストラクトを作ることができる。
package main import "fmt" type MyInt int func (i MyInt) Double() int { fmt.Printf("%T %v\n", i, 1) fmt.Printf("%T %v\n", 1, 1) return int(i * 2) } func main() { myInt := MyInt(10) fmt.Println(myInt.Double()) }
インターフェース
よくわからなくなるインターフェース。
DriveCarはHumanインターフェースのみの引数なので別のインターフェースは宣言できない。
package main import "fmt" type Human interface { Say() string } type Person struct { Name string } func (p *Person) Say() string { p.Name = "Mr" + p.Name fmt.Println(p.Name) return p.Name } func DriveCar(human Human) { if huma.Say() == "Mr.Mike" { fmt.Println("Run") } else { fmt.Println("Get out") } } func main() { var mike Human = &Person{"Mike"} var x Human = &Person{"X"} DriveCar(mike) DriveCar(mike) }
type-switch文
sitch文で各文字のtypeによって条件判別できる。
package main import "fmt" func do(i interface{}) { switch v := i.(type) { case int: fmt.Println(v * 2) case string: fmt.Println(v + "!") default: fmt.Printf("I don't know %T\n", v) } } func main() { do(10) do("Mike") do(true) var i int = 10 ii := float64(10) fmt.Println(i, ii) }
stringer
stringerを作ると下記のコードなら本来であれば構造体の中身がすべて出力されるがstringerで作ったものが出力される。
package main import "fmt" type Person struct { Name string Age int } func (p Person) String() string { return fmt.Sprintf("My name is %v.", p.Name) } func main() { mike := Person{"Mike", 22} fmt.Println(mike) }
カスタムエラー
カスタムエラーを作る際はポインタを引数に渡すような設計にする。
func (e *UserNotFound) Error() string { return fmt.Sprintf("User not found: %v", e.Username) }
goroutine
やっぱり理解するのは難しそう。
なれていくしかないのかな。
channel
channelはなんとなく理解できそう。
キューの状態で持たせてそのデータを取り出すイメージ。
package main import "fmt" func goroutine1(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum } func goroutine2(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum } func main() { s := []int{1, 2, 3, 4, 5} c := make(chan int) go goroutine1(s, c) go goroutine2(s, c) x := <-c fmt.Println(x) y := <-c fmt.Println(y) }
channelをfor文でループさせたい場合はclose()で一度channelを閉じる。
package main import "fmt" func main() { ch := make(chan int, 2) ch <- 100 fmt.Println(len(ch)) ch <- 200 fmt.Println(len(ch)) close(ch) for c := range ch { fmt.Println(c) } }