Go言語マスター 〜ループ処理・条件分岐〜

公開日:2022-09-04
go

https://youtu.be/5lhK4SVVGMc

はじめに

Goの条件分岐・ループ処理・条件分岐について解説します。

For

まずはループ処理の基本のfor文についてです。

package main

import "fmt"

func main() {
  sum := 0
  for i := 0; i < 10; i++ {
    sum += i
  }
  fmt.Println(sum)
}

for文は3つのセミコロンで区切られて表現されます。最初は変数の初期化で今回は変数iを初期化しています。2つ目はループを継続するかの条件式です。今回は10よりも小さいという条件を入れています。3つ目は後処理で、今回は変数iを加算しています。

今回は、for文の中で0から9まで値を加算していて出力は45となります。

for contiuned

通常のFor文を少し変形した形についてです。

package main

import "fmt"

func main() {
  sum := 1
  for ; sum < 1000; {
    sum += sum
  }
  fmt.Println(sum)
}

変数の初期化がfor文の上で行い、後処理がfor文の処理部分で記述されて、全体的に記述量が少なくできます。

For is Go's 'while'

他の言語にはwhile文というものが存在していますが、Goではwhile文は存在しません。そのためGoでのwhile文の代わりとなる記述方法について説明します。

package main

import "fmt"

func main() {
  sum := 1
  for sum < 1000 {
    sum += sum
  }
  fmt.Println(sum)
}

for文の中にセミコロンがありましたが今回はありません。このようにすることで他の言語のwhileの同じことができます。
今回は変数sumが1000より大きくなるまでループするという処理になります。

Forever

次は無限ループについてです。

package main

func main() {
  for {
  }
}

for文の条件部分がなくなりました。条件部分をなくすことで無限ループとなります。

条件分岐

if

条件分岐の基本であるif文についてです。

package main

import (
  "fmt"
  "math"
)

func sqrt(x float64) string {
  if x < 0 {
    return sqrt(-x) + "i"
  }
  return fmt.Sprint(math.Sqrt(x))
}

func main() {
  fmt.Println(sqrt(2), sqrt(-4))
}

sqrt関数の中でif文が使用されています。ちなみにこのプログラムは平方根を計算するプログラムとなっています。

If with a short statement

if文は、for文のように条件の前に評価するための簡単なステートメントを書くことができます。

package main

import (
  "fmt"
  "math"
)

func pow(x, n, lim float64) float64 {
  if v := math.Pow(x, n); v < lim {
    return v
  }
  return lim
}

func main() {
  fmt.Println(
    pow(3, 2, 10),
    pow(3, 3, 20),
  )
}

関数powの中にあるif文の説明をします。このif文はfor文のようにセミコロンで区切ります。区切った最初の部分は、if文を実行する前に実行する処理です。

if and else

if-else文についてです。

package main

import (
  "fmt"
  "math"
)

func pow(x, n, lim float64) float64 {
  if v := math.Pow(x, n); v < lim {
    return v
  } else {
    fmt.Printf("%g >= %g\n", v, lim)
  }
  // can't use v here, though
  return lim
}

func main() {
  fmt.Println(
    pow(3, 2, 10),
    pow(3, 3, 20),
  )
}

else節はif文の条件式以外の時に実行されます。

switch

switch文は、if-else文を短く書くことができる構文です。

package main

import (
  "fmt"
  "runtime"
)

func main() {
  fmt.Print("Go runs on ")
  switch os := runtime.GOOS; os {
  case "darwin":
    fmt.Println("OS X.")
  case "linux":
    fmt.Println("Linux.")
  default:
    // freebsd, openbsd,
    // plan9, windows...
    fmt.Printf("%s.\n", os)
  }
}

他の言語と同じようなSwitch文ですが、Goではbrakeが不要でどの条件にも属さなければdefaultに入ります。

Switch evaluation order

Switchが実行される順番について説明をします。

package main

import (
  "fmt"
  "time"
)

func main() {
  fmt.Println("When's Saturday?")
  today := time.Now().Weekday()
  switch time.Saturday {
  case today + 0:
    fmt.Println("Today.")
  case today + 1:
    fmt.Println("Tomorrow.")
  case today + 2:
    fmt.Println("In two days.")
  default:
    fmt.Println("Too far away.")
  }
}

Switch文は条件が上から下へ実行されていき、caseの条件が一致したところで終了をします。他の言語と異なる点は、caseの条件に式を入れられる点です。

Defer

関数を遅延させる方法について説明します。

package main

import "fmt"

func main() {
  defer fmt.Println("world")
  fmt.Println("hello")
}

deferは、 deferへ渡した関数の実行を、呼び出し元の関数の終わり(returnする)まで遅延させます。
このサンプルにあるdeferは、helloを出力した後なので出力としては、hello worldとなります。

Stacking defers

deferが複数ある場合について説明をします。

package main

import "fmt"

func main() {
  fmt.Println("counting")

  for i := 0; i < 10; i++ {
    defer fmt.Println(i)
  }

  fmt.Println("done")
}

deferが複数存在する場合は実行をスタックできます。今回は、for文の中で0から9までを表示するようになっているため、その実行をスタックしていきdoneが表示された後に、9から0が表示されます。

deferを使うときの具体例としてファイルを操作があります。ファイルを操作する時は、openとcloseを行う必要があります。
例えば、ファイルをopenした後にエラーが発生した場合、close処理が行われないとメモリリークしてしまいます。それを防ぐためにファイルをopenした後にdeferを使用してclose処理を書いておくことで、最終的に必ずcloseが実行されることになるため、メモリリークが発生しなくなります。

おわりに

今回は、Goでのループ処理・条件分岐について解説しました。