LoginSignup
0
0

More than 3 years have passed since last update.

Golang 基礎 (struct周り)part2

Last updated at Posted at 2020-08-11

part1の続き

makeとnewの違い

どちらも値を入れずメモリ領域を確保する。違いはポインタが返ってくるかどうか。

// 返ってこない
s := make([]int, 0)
m := make(map[string]int)
ch := make(chan int)

// 返ってくる
var p *int = new(int)
var st = new(struct{})

cf. 中身はnil (メモリ確保していない)

var s []int
var m map[string]int
var ch chan int
var p *int 

struct

type Vertex struct {
    X, Y int
    S string
}

v1とv2は同じ意味。v3とv4は同じ意味。

v1 := Vertex{} // {0 0  }
var v2 Vertex // {0 0  }

v3 := new(Vertex) // &{0 0  }
v4 := &Vertex{} // &{0 0  }
    changeVertex := func(v Vertex) {
        v.X = 1000
    }
    changeVertex2 := func(v *Vertex) {
        v.X = 1000 // (*v).X = 1000 と同じ意味になる
    }

    v := Vertex{1, 2, "test"}

    changeVertex(v) // 値渡し
    fmt.Println(v) // {1 2 test} 値が書き換わっていない
    changeVertex2(&v) // 参照渡し
    fmt.Println(v) // {1000 2 test} 値が書き換わっている

structオリエンテッド

package main

import "fmt"

type Vertex struct {
    x, y int // 先頭が小文字だとpackage内からのみ参照可能
}

// メソッド(値レシーバー)
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
}

// Embedded(継承みたいなやつ)
type Vertex3D struct {
    Vertex
    z int
}

func (v Vertex3D) Area3D() int {
    return v.x * v.y * v.z
}

func (v *Vertex3D) Scale3D(i int) {
    v.x *= i
    v.y *= i
    v.z *= i
}

// コンストラクタ
func New(x, y, z int) *Vertex3D {
    return &Vertex3D{Vertex{x, y}, z}
}

func main() {
    v := New(4, 5, 6)
    v.Scale3D(10)
    fmt.Println(v.Area()) // 継承元のメソッドも使える
    fmt.Println(v.Area3D())
}

non-struct

自分なりの型とメソッドを作れる。

type MyInt int

func (i MyInt) Double() int {
    return int(i * 2)
}

インターフェースとダックタイピング

package main

import "fmt"

// 設計書みたいなイメージ
type Human interface {
    Say() string // 実装しないといけない関数を書く
}

type Person struct {
    Name string
}

func (p Person) Say() string {
    return "Mr." + p.Name
}

// インターフェースのダックタイピング(Say()というメソッドがないと成立しないときに使う)
func DriveCar(human Human) {
    if human.Say() == "Mr.Mike" {
        fmt.Println("Run")
    } else {
        fmt.Println("Get out")
    }
}

func main() {
    var mike Human = Person{"Mike"} // Humanにstructを入れたら、Say()というメソッドがないとだめ
    DriveCar(mike)
}

タイプアサーションとswitch type文

// 引数が interface{} →何でも引数として受け入れる!
func do(i interface{})  {
    /* タイプアサーション: interfaceを他の型に変える
    ii := i.(int)
    ss := i.(string) など
    */

    // switch type 文
    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)

    }
}

Stringer

package main

import "fmt"

type Person struct {
    Name string
    Age int
}

// String()のメソッドを実装すれば fmt の出力を変えることができる!
func (p Person) String() string {
    return fmt.Sprintf("My name is %v, I'm %v years old.", p.Name, p.Age)
}

func main() {
    mike := Person{"Mike", 20}
    fmt.Println(mike) // My name is Mike, I'm 20 years old.
}

カスタムエラー

package main

import "fmt"

// 自分なりのエラーを作る
type UserNotFound struct {
    Username string
}

// 作ったエラーにError()のメソッドを実装するとエラー時にこれが出力される
func (e *UserNotFound) Error() string {
    return fmt.Sprintf("User not found: %v", e.Username)
}

func myFunc() error {
    // something wrong
    ok := false
    if ok {
        return nil
    }
    return &UserNotFound{Username: "mike"}
}


func main() {
    if err := myFunc(); err != nil{
        fmt.Println(err) // User not found: mike
    }
}

Error()をポインタレシーバーにする理由:エラーが違う場所で起きたときに比較判定するため。
以下サンプルコード。err == io.EOFの部分。
err == errors.New("EOF")としてもうまく行かない。→ r.Read()が io.EOFというエラーを返すため。

package main

import (
    "fmt"
    "io"
    "strings"
)

func main() {
    r := strings.NewReader("Hello, Reader!")

    b := make([]byte, 8)
    for {
        n, err := r.Read(b)
        fmt.Printf("n=%v err=%v b=%v\n", n, err, b)
        fmt.Printf("b[:n]=%q\n", b[:n])
        if err == io.EOF{
            break
        }
    }
}

参考

現役シリコンバレーエンジニアが教えるGo入門 + 応用でビットコインのシストレFintechアプリの開発

part3

0
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
0
0