Goことはじめ2
第2章 基本文法―覚えやすいコンパクトな言語仕様:はじめてのGo―シンプルな言語仕様,型システム,並行処理|gihyo.jp … 技術評論社
より学んだことメモ。
基本的な文法について
package main import ( "fmt" "os" "errors" "log" // f "fmt" -> と記述すると f.Println()のようにアクセスできる // . "strings" -> と記述すると ToUpper('xx') とパッケージ指定なしでアクセスできる ) // // 代入処理について // func substitute() { fmt.Println("substitute -------------------- ") // 変数代入 var message string = "hello world" fmt.Println(message) // 関数の中では型推論して代入もできる message2 := "hello world" fmt.Println(message2) // 定数定義 const Hello string = "Hello Const" // 変数を宣言して明示的に初期化しなかった場合は // ゼロ値で初期化される // 整数型: 0 // 浮動小数点型: 0.0 // bool: false // string: "" // 配列: 各要素がゼロ値の配列 // 構造体: 各フィールドがゼロ値の構造体 // そのほかの型: nil const message3 string = ` 複数行に渡る 文字列を使うときは バッククォートでくるる ` } // // 条件分岐・繰り返し // func repeat() { fmt.Println("repeat -------------------- ") // if文 Goでは丸かっこは不要 a, b := 10, 100 if a > b { fmt.Println("a is larger than b") } else if a < b { fmt.Println("a is smaller than b") } else { fmt.Println("a equals b") } // 繰り返しはfor文だけ n := 0 for n < 10 { fmt.Printf("n = %d\n", n) n++ } // 無限ループ・break・continue m := 0 for { m++ if m > 10 { break // ループを抜ける } if m%2 == 0 { continue // 偶数なら次の繰り返しに映る } fmt.Println(m) // 奇数のみ表示 } // switch文 // breakは書かなくていい p := 10 switch p { case 15: fmt.Println("FizzBuzz") case 10: fmt.Println("Buzz") case 3, 6, 9: // カンマ切りで複数指定可能 fmt.Println("Fizz") // そのまま下に処理をおろしたい場合は // fallthrough // と記述する(逆break) default: fmt.Println(p) } // if文と同じようにかける q := 10 switch { case (p % 15 == 0): fmt.Println("FizzBuzz") case (p % 5 == 0): fmt.Println("Buzz") default: fmt.Println(q) } } // // 関数 // // 引数の後に型を指定する func sum1(i, j int) { // func sum(i int, j int) と同じ fmt.Println(i + j) } // 戻り値がある場合は引数の次に指定する func sum2(i, j int) int { return i + j } // 関数は複数の値を返せる func swap(i, j int) (int, int) { return j, i } // 内部で発生したエラーは戻り値で表現する func errorFunc() { // _ で 第1戻り値を無視 _, err := os.Open("sample.txt") if err != nil { // エラー処理 fmt.Println("file open error") } fmt.Println("file open success") } // 自作のエラーはerrorsパッケージを用いて作ることができる func div(i, j int) (int, error) { if j == 0 { // 自作のエラーを返す return 0, errors.New("divied by zero") } return i / j, nil } // 名前付き戻り値 // 関数内ではゼロ値で初期化された変数として扱われる func divWithName(i, j int) (result int, err error) { if j == 0 { err = errors.New("divied by zero") return // return 0, err と同じ } result = i / j return // return result, nil と同じ } // 関数はオブジェクト func wrapFunc() { // 関数リテラル(無名関数) // 即時実行される func(i, j int) { fmt.Println(i + j) }(2, 4) // 関数は変数に代入できる var sum func(i, j int) = func(i, j int) { fmt.Println(i + j) } sum(2, 3) } // // 配列 // func arrayFunc() { fmt.Println("arrayFunc -------------------- ") // Goの配列は固定長 var arr [4]string arr[0] = "a" arr[1] = "b" arr[2] = "c" arr[3] = "d" fmt.Println(arr[0]) // 宣言と代入 arr2 := [4]string{"a", "b", "c", "d"} fmt.Println(arr2) // 暗黙的なサイズ指定 arr3 := [...]string{"a", "b", "c", "d"} fmt.Println(arr3) // 長さの違う配列は別の型 // 関数に配列を渡す場合は"値渡し"になる } // // スライス // スライスは,可変長配列として扱うことができます。 // 配列を直接使うのは,シビアなメモリ管理が必要な一部のプログラムだけなので, // 基本的にはスライスを用います。 // func sliceFunc() { fmt.Println("sliceFunc -------------------- ") // スライスの型には長さの情報はない var s []string // 追加 s = append(s, "a") // 追加した要素を返す s = append(s, "b") s = append(s, "c", "d") fmt.Println(s) // [a b c d] // 結合 s1 := []string{"a", "b"} s2 := []string{"c", "d"} s1 = append(s1, s2...) // s1にs2を追加 fmt.Println(s1) // [a b c d] // 繰り返し処理 // rangeは配列,スライス,string,マップに対して使うことができる s11 := []string{"a", "b", "c", "d"} for i, v := range s11 { // i = 添字, v = 値 fmt.Println(i, v) } // 値の切り出し s21 := []int{1, 2, 3, 4, 5} fmt.Println(s21[2:4]) // [2 3] fmt.Println(s21[0:len(s)]) // [0 1 2 3 4 5] fmt.Println(s21[:3]) // [0 1 2] fmt.Println(s21[3:]) // [3 4 5] fmt.Println(s21[:]) // [0 1 2 3 4 5] // 可変長引数 var _sum func(nums ...int) (result int) = func(nums ...int) (result int) { // numsは []int型 for _, n := range nums { result += n } return } fmt.Println(_sum(1, 2, 3, 4)) // 10 } // // マップ // マップは値をKey-Valueの対応で保存するデータ構造 // func mapFunc() { fmt.Println("mapFunc -------------------- ") // 宣言 key=int, value=string var month map[int]string = map[int]string{} month[1] = "January" month[2] = "February" fmt.Println(month) // 宣言と初期化を一緒にする場合 month2 := map[int]string { 1: "January", 2: "February", } fmt.Println(month2) // 値を取り出す jan := month[1] fmt.Println(jan) // マップにキーが存在するかチェック _, ok := month[1] if ok { fmt.Println("month[1] is present") } // 要素の削除 delete(month, 1) // 繰り返し処理 // 処理順番は保証されない for key, value := range month { fmt.Printf("%d %s\n", key, value) } } // // ポインタ // ポインタを使うことで参照渡しができる // func callByValue(i int) { i = 20; // 値を上書きする } func callByRef(i *int) { *i = 20; // 参照先を上書きする } // // 関数を抜けるときに必ず実行 // func deferFunc() { fmt.Println("deferFunc -------------------- ") file, err := os.Open("./error.go") if err != nil { fmt.Println("FileOpenError") } // 関数を抜ける前に必ず実行される defer file.Close() // 正常処理 fmt.Println("deferFuncProcess") } // // パニックと後処理 // func panicFunc() { fmt.Println("PanicFunc -------------------- ") // 後処理 defer func() { // パニックで発生したエラーはrecoverで取得できる err := recover() if err != nil { log.Print(err) } }() a := []int{1, 2, 3} fmt.Println(a[10]) // パニック発生 // 自前でパニックを起こすこともできる // panic(errors.New("index out of range")) } func main() { substitute() repeat() fmt.Println("Function -------------------- ") sum1(1, 2) s := sum2(2, 3) fmt.Println(s) x, y := swap(3, 4) fmt.Println(x, y) errorFunc() _, err := div(10, 0) if err != nil { log.Print(err) // Fatalを使用するとステータス=1で終了する // log.Fatal(err) } m, err := divWithName(10, 2) fmt.Println(m) wrapFunc() arrayFunc() sliceFunc() mapFunc() fmt.Println("Pointer -------------------- ") var i int = 10; callByValue(i) // 値渡し fmt.Println(i) // 10 callByRef(&i) // 参照渡し fmt.Println(i) // 20 deferFunc() panicFunc() }