コピペコードで快適生活

明日使えるソースを自分のために

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()
}