Golang入門編〜分岐処理・ファイル処理〜

前書き

前回の続きです。前回は変数定義〜配列までの基礎文法を勉強していきました。
今回は分岐処理をメインに勉強していこうと思います。

melheaven.hatenadiary.jp

基礎文法

関数の応用(クロージャー)

Golang独特なイディオム。
クロージャとは簡潔的に言うと「関数と関数の処理に関係する関数外の環境を閉じ込めた無名関数」。
引数以外の変数を実行時の環境ではなく、自身が定義された環境を保持します。

qiita.com

以下はPI=3.14、r=1(引数)で円の面積を計算したプログラムとなっています。

  1. Area(3.14)で関数を呼び出し
  2. Area関数内のn:=0が実行
  3. Area関数内の円面積計算が実行(n=1)
  4. Area関数内の円面積計算が実行(n=2)
  5. Area関数内の円面積計算が実行(n=3)

クロージャと結びつく限り、nは破棄されません。

// 引数は関数呼び出し時のみ格納
// メソッドを繰り返すとreturn 内のみ実行
func Area(pi float64) func(r float64) float64{
    n := 0
    return func(r float64) float64{
        n += 1
        return pi*r*r*float64(n)
    }
}

func main(){
    c1 := Area(3.14)
    fmt.Println(c1(1))
    fmt.Println(c1(1))
    fmt.Println(c1(1))
}

可変長引数

関数の引数に長さに依存しない配列を受け入れるように可変長引数の勉強をします。
スライスの変数の後ろに...を付けて関数を呼び出します。

qiita.com

// ...→引数を可変状に
func variable(params ...int){
    fmt.Println(len(params), params)
    for _, param := range params{
        fmt.Println(param)
    }
}

func main(){
    fmt.Println("variable--------------------")
    variable(19,200,3300)
    
    moreList := []int{1,2,3,3,4,5,56}
    // 配列を可変状に展開して関数を動作-> ...
    variable(moreList...)
}
variable--------------------
3 [19 200 3300]
19
200
3300

7 [1 2 3 3 4 5 56]
1
2
3
3
4
5
56

if-else文

2種類の記法を書いておきます。

func main(){
    fmt.Println("if_else--------------")
    num := 9
    if num % 2 == 0 {
        fmt.Println(num)
    }else if num % 3 == 0 {
        fmt.Println("by 3")
    }else{
        fmt.Println("else")
    }

    if num := 9; num==9{
        fmt.Println("OK")
    }
}
if_else--------------
by 3
OK

for文

for文の記法はCに非常に近いです。

for i := 0; i < 10; i++ {
        if i == 3{
            fmt.Println("continue")
            continue
        }
        if i > 5{
            fmt.Println("break")
            break
        }
        fmt.Println(i)
    }
0
1
2
continue
4
5
break

for文とrange

配列に対しての展開

rangeを活用する事で、forよりもさらに簡潔に配列の要素・値を展開できます。

func main(){
    fmt.Println("range--------------")
    l := []string{"China", "USA", "Japan"}
    
    for i := 0 ;i < len(l); i++{
        fmt.Println(i, l[i])
    }
    
    for i, v := range l {
        fmt.Println(i, v)
    }
}
range--------------
0 China
1 USA
2 Japan
0 China
1 USA
2 Japan
連想配列に対しての展開
func main(){
    m := map[string]int{"matsui": 55, "ichiro": 51}
    for k, v := range m{
        fmt.Println(k, v)
    }
    for k := range m{
        fmt.Println(k)
    }
}
matsui 55
ichiro 51
matsui
ichiro

switch文

func main(){
    fmt.Println("switch--------------")
    player := "Ichiro"
    switch player {
        case "Matsui": fmt.Println("55!!")
        case "Ichiro": fmt.Println("51!!")
        default:
            fmt.Println("None")
    }
}
switch--------------
51!!

Defer

defer文とは、記述されている関数内の上位ブロックの関数からreturnで返されるまで、関数に実行を遅らせる役目を持ちます。「ファイルを開いた→ファイルの読み書き→ファイルを閉じる」の処理が発生するとします。この場合、「ファイルを閉じる」処理にてDefer文を置きます。するとファイル使用時の処理を全て完了させた後、deferの処理が実行されます。上記のような例だと大変都合が良いわけです。

func main(){
    defer fmt.Println("1")
    defer fmt.Println("2")
    defer fmt.Println("3")
}
3
2
1

以下の処理の場合、次の順番で処理が実行されます。

  1. Main.goを開く
  2. 20バイトのスライスを作成
  3. ファイルから20バイト分読む混む
  4. 読み込んだ部分を表示
  5. ファイルを閉じる
func openfile(){
    file, _ := os.Open("./Main.go")
    defer file.Close()
    data := make([]byte, 20)
    file.Read(data)
    fmt.Println(string(data))
}