LoginSignup
2
0

More than 3 years have passed since last update.

A Tour of Go メモ ~Flow control statements: for, if, else, switch and defer~

Last updated at Posted at 2020-12-07

はじめに

Go の勉強のため、A Tour of Goに取り組んでいる
今回はFlow control statements: for, if, else, switch and defer章について、学んだことを記していく

まとめ記事はこちら

使えそうなスニペット

※筆者は VSCode を使用

for

初期値、条件式、後処理、スコープ内部の順にカーソルが移動する

for i := 0; i < count; i++ {

}

if

条件式、スコープ内部にカーソルが移動する
el -> else { } で else ブロックを追加できる

if condition {

}

ei

一発でも作れる

if condition {

} else {

}

switch

条件式、case、スコープ内部にカーソルが移動する
cs -> case condition: で条件を追加できる

switch expression {
case condition:

}

df

defer func()

pn

panic("")

recover

こちらは存在しなかったので、自作した
(Preferences: Configure User Snippetsコマンドから作成可能)
出力されるのは、

defer func() {
        if r := recover(); r != nil {

        }
}()

User Snippet の Json は、

    "defer recover": {
        "prefix": "recover",
        "body": [
            "defer func() {",
            "    if r := recover(); r != nil {",
            "        $1",
            "    }",
            "}()",
        ],
        "description": "defer recover"
    }

ページごとの補足

For continued

for 文で定義した変数を、条件式で使わなくても良い

    x := 1
    for i := 0; 0 < x; {
        fmt.Println(i) // 流石にスコープ内で使わないと怒られる
    }

for で定義する変数は、定義済みでも良い

    x := 1
    for x = 0; x < 10; x++ {
        fmt.Println(x)
  }

If and else

  • if ステートメントで宣言された変数は、else ifブロック内でも使える
  • else ifステートメントで宣言された変数も、後続のelse ifelseブロック内でも使える
  • 同じ名前の変数を宣言した場合、上書きされる(=スコープがネストされる?)
    x := 1 // 1,2,3,4
    if y := 1; x == 1 {
        fmt.Println("x == 1 : y = ", y)
    } else if y := 2; x == 2 {
        fmt.Println("x == 2 : y = ", y)
    } else if y := 3; x == 3 {
        fmt.Println("x == 3 : y = ", y)
    } else {
        fmt.Println("x  > 3 : y = ", y)
    }
    // x == 1 : y = 1
    // x == 2 : y = 2
    // x == 3 : y = 3
    // x  > 3 : y = 3

Switch with no condition

Switch の case の条件式では変数宣言ができないため、例えば上述したif-elseは、置き換えることができなさそう

Defer

A Tour of Goでは言葉少なに紹介されているため、Defer, Panic, and Recover(日本語訳は こちら)の内容がメインになる

defer の使い方の 1 つは、他言語でいうfinally
(Python でいうwith、Kotlin でいうuseの代わりにもなる)

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()

    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()

    return io.Copy(dst, src)
}

他にも panic, recover があり、それぞれ以下のように対応しそう

  • panic: throw error
  • recover: catch

以下はエラーハンドリングについて、公式のサンプルプログラム

package main

import "fmt"

func main() {
    f()
    fmt.Println("Returned normally from f.")
}

func f() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in f", r)
        }
    }()
    fmt.Println("Calling g.")
    g(0)
    fmt.Println("Returned normally from g.")
}

func g(i int) {
    if i > 3 {
        fmt.Println("Panicking!")
        panic(fmt.Sprintf("%v", i))
    }
    defer fmt.Println("Defer in g", i)
    fmt.Println("Printing in g", i)
    g(i + 1)
}

これを実行すると、以下のようになる

Calling g.
Printing in g 0
Printing in g 1
Printing in g 2
Printing in g 3
Panicking!
Defer in g 3
Defer in g 2
Defer in g 1
Defer in g 0
Recovered in f 4
Returned normally from f.

少し癖がありますが、使い慣れると便利そう
何度もtry-catchを書かずに済みそうだ

雑感

このあたりは他言語と似通った仕様が多いので、難しい印象はない(最後の defer は別だが)
Go 言語は言語の仕様変更・追加が少ないので、数年前の記事が当てになるのが良い

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0