たなしょのメモ

日々勉強していることをつらつらと

7/20 週報

週報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)
    }
}