LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

Organization

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

はじめに

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 言語は言語の仕様変更・追加が少ないので、数年前の記事が当てになるのが良い

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
What you can do with signing up
0