技術めも

Go 言語 02

type

適切な型を自分で用意(型のAlias)

type ID int
type Priority int

func ProcessTask(id ID, priority Priority) {
}

var id ID = 3
var priority Priority = 5
ProcessTask(priority, id) // コンパイルエラー

構造体(struct、class)

大文字で始まる場合はパブリック,小文字の場合はパッケージ内に閉じたスコープ
初期値指定がない場合はゼロ値で初期化

// Taskという型を定義
type Task struct {
    ID int
    Detail string
    done bool
}

// 値を生成
var mytask Task = Task{
        ID: 1,
        Detail: "buy the milk",
        done: true,
}

mytask.ID
mytask.Detail
mytask.done
// フィールド名省略
var task Task = Task{
        1, "buy the milk", true,
}

構造体の名前の前に * を付けるとポインタ型になる

var mytask Task = Task{} // Task型
var mytask *Task = &Task{} // Taskのポインタ型

ポインタ型(参照渡)

構造体の名前の前に & を付けると,変数にはアドレスが格納
Taskのポインタ型は*Taskという型

func Finish(task *Task) {
    task.done = true
}

task := &Task{done: false}
Finish(task)
fmt.Println(task.done)     // ポインタ型からでもフィールドにアクセス可能

new()

構造体は new() を用いて初期化することもできます
すべてゼロ値で初期化しそのポインタを返します

var mytask *Task = new(Task)
mytask.ID = 1
mytask.Detail = "buy the milk"
fmt.Println(mytask.done) // false

コンストラクタ

ない
Newで始まる関数を定義しその内部で構造体を生成するのが通例

func NewTask(id int, detail string) *Task {
    task := &Task{
        ID: id,
        Detail: detail,
        done: false,
    }
    return task
}

mytask := NewTask(1, "buy the milk")

メソッド

func (task Task) String() string {
    str := fmt.Sprintf("[%d] %s", task.ID, task.Detail)
    return str
}

task := NewTask(1, "buy the milk")
fmt.Printf(“%s”, task)

値を変更する必要がある場合はポインタ渡し

func (task *Task) Finish() {
    task.done = true
}

mytask := NewTask(1, "buy the milk")
mytask.Finish()

インタフェース

その型がどのようなメソッドを実装するべきかを規定する

// 宣言
type Stringer interface {
    String() string
}

// 実装
func Print(stringer Stringer) {
    fmt.Println(stringer.String())
}

Print(task)

型の埋め込み(継承)

構造体型宣言時に,フィールドではなく型のみを記述することで,その型を埋め込むことができる

// User 構造体
type User struct {
    FirstName string
    LastName string
}

func (u *User) FullName() string {
    fullname := fmt.Sprintf("%s %s",
        u.FirstName, u.LastName)
    return fullname
}

func NewUser(firstName, lastName string) *User {
    return &User{
        FirstName: firstName,
        LastName: lastName,
    }
}
type Task struct {
    ID int
    Detail string
    done bool
    *User // Userを埋め込む
}

func NewTask(id int, detail,
    firstName, lastName string) *Task {
    task := &Task{
        ID: id,
        Detail: detail,
        done: false,
        User: NewUser(firstName, lastName),
    }
    return task
}

継承のようにメソッド呼び出しできる

task := NewTask(1, "buy the milk", "Jxck", "Daniel")

task.FirstName
task.LastName
task.FullName()
task.User

型の変換

キャストに失敗した場合はパニックが発生

var i uint8 = 3
var j uint32 = uint32(i)

var s string = "abc"
var b []byte = []byte(s)

a := int("a")

Type Assertion(型の検査)

func Print(value interface{}) {
    s, ok := value.(string)            // string かどうか?
    if ok {
        fmt.Printf("value is string: %s\n", s)
    } else {
        fmt.Printf("value is not string\n")
    }
}

Type Switch(型による分岐)

type Stringer interface {
    String() string
}

func Print(value interface{}) {
    switch v := value.(type) {
    case string:
        fmt.Printf("value is string: %s\n", v)
    case int:
        fmt.Printf("value is int: %d\n", v)
    case Stringer:
        fmt.Printf("value is Stringer: %s\n", v)
    }
}