Golang ことはじめ typeとstruct
type
独自の型を定義することが可能。
例えば以下の構文は引数の順番が 間違っていても コンパイルが通ってしまう。
func main(){ id := 1 priority := 5 // 両方ともint型なため、コンパイルが通る ProcessTask(priority, id) } func ProcessTask(id, priority int) { ... }
そこで、typeを使い、独自の型宣言をすることで解決することが可能
type ID int type Priority int func main(){ var id ID = 1 var priority Priority = 5 // 引数の型が違うためコンパイルエラー ProcessTask(priority, id) // これは型が一致しているため通る ProcessTask(id, priority) } func ProcessTask(id ID, priority Priority){ ... }
構造体(struct)
データをひとまとめにした型だと思えば良い。
一般的なクラス構文的役割も果たす。
// 構造体 type Task struct { ID int Detail string done bool } func main() { // 構造体初期化 var task Task = Task{ ID: 1, Detail: "buy the milk", done: true, } // 構造体順に定義すると、フィールド名を省略できる // var task Task = Task{1, "buy the milk", true,} // または下記のように型推論可能 // task := Task{1, "buy the milk", true,} fmt.Println(task.ID) //1 fmt.Println(task.Detail) //buy the milk fmt.Println(task.done) //true // 構造体のポインタ利用 StructPointer() // コンストラクタ task2 := NewTask(1, "buy the milk") fmt.Printf("%+v", task2) // メソッド task3 := NewTask(1, "buy the popcorn") fmt.Printf("%s", task3) } // 構造体に明示的な値を指定しない場合、すべてゼロ値となる func ZeroTask() { task := Task{} fmt.Println(task.ID) //0 fmt.Println(task.Detail) // "" fmt.Println(task.done) //false } // 構造体のポインタ利用 func StructPointer() { task := &Task{done: false} Finish(task) fmt.Println(task.done) //true } func Finish(task *Task) { task.done = true } /** * コンストラクタ例 * Goには構造体のコンストラクタに当たる構文がないため、 * 代わりにNewで始まる関数を定義するのが通例 * 内部でTask構造体を生成し、そのポインタを返す */ func NewTask(id int, detail string) *Task { task := &Task{ ID: id, Detail: detail, done: false, } return task } /** * メソッド(レシーバ) * メソッドを「実行した」対象の型をレシーバとして受け取り、内部で使用できる */ func (task3 Task) String() string { str := fmt.Sprintf("%d) %s", task3.ID, task3.Detail) return str }
一般的なクラス構文のオブジェクト指向よりわかりやすい気がする。
ただ、クラス構文に慣れすぎてると戸惑いがあった。
次回はインターフェースについて。