[Goのはじめ方] Part7: 制御構文(if, for, switch)

Go

プログラムは通常、上から下へと順番に実行されますが、時には条件によって処理を変えたり、同じ処理を繰り返したりする必要があります。Go言語では、そのような制御を行うために if文、for文、switch文が用意されています。これらを使いこなして、より柔軟なプログラムを作成しましょう! 💪

if文:条件による分岐 🤔

if文は、指定した条件が真 (true) か偽 (false) かによって、実行する処理を分岐させます。

基本的なif文

条件式が true の場合に、続くブロック { } 内の処理を実行します。

package main

import "fmt"

func main() {
	score := 85
	if score > 80 {
		fmt.Println("素晴らしい!合格です! 🎉") // score > 80 が true なので実行される
	}
}

if-else文

条件式が true の場合と false の場合で、それぞれ異なる処理を実行します。

package main

import "fmt"

func main() {
	age := 18
	if age >= 20 {
		fmt.Println("成人です。")
	} else {
		fmt.Println("未成年です。") // age >= 20 が false なのでこちらが実行される
	}
}

if-else if-else文

複数の条件で分岐させたい場合に使用します。

package main

import "fmt"

func main() {
	score := 75
	if score >= 90 {
		fmt.Println("優")
	} else if score >= 80 {
		fmt.Println("良")
	} else if score >= 70 {
		fmt.Println("可") // score >= 70 が true なのでこちらが実行される
	} else {
		fmt.Println("不可")
	}
}

簡易ステートメント付きif文

Goの特徴的な書き方として、if の条件式の前に簡単なステートメント(通常は変数宣言と初期化)を書くことができます。ここで宣言された変数のスコープ(有効範囲)は、if 文とその else if / else ブロック内に限定されます。これはコードを簡潔にし、変数の影響範囲を狭めるのに役立ちます。✅

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	// Go 1.20 より前では Seed の設定が推奨されていました
	// rand.Seed(time.Now().UnixNano())

	// 簡易ステートメントで乱数を生成し、その値で分岐
	if n := rand.Intn(10); n > 5 {
		fmt.Printf("%d は 5 より大きい\n", n)
		// 変数 n はこの if ブロック内でのみ有効
	} else {
		fmt.Printf("%d は 5 以下\n", n)
		// 変数 n はこの else ブロック内でのみ有効
	}
	// fmt.Println(n) // ここでは n は使えない (スコープ外)
}
ポイント: 簡易ステートメントで宣言された変数のスコープは if (および関連する else if/else) ブロック内に限定されます。

for文:繰り返し処理 🔁

Go言語の繰り返し処理は for文のみで表現されます。他の言語にある whiledo-while に相当する構文はありませんが、for文の柔軟な書き方でそれらを表現できます。

基本形 (C言語スタイル)

初期化ステートメント、条件式、後処理ステートメントを指定します。

package main

import "fmt"

func main() {
	sum := 0
	// 1から10までの合計を計算
	for i := 1; i <= 10; i++ { // 初期化; 条件; 後処理
		sum += i
	}
	fmt.Println("合計:", sum) // 合計: 55
}

条件のみ (whileスタイル)

条件式のみを指定すると、その条件が true である間、繰り返し処理を実行します。

package main

import "fmt"

func main() {
	n := 1
	// nが100未満の間、2倍し続ける
	for n < 100 {
		n *= 2
	}
	fmt.Println("結果:", n) // 結果: 128
}

無限ループ

条件式を省略すると無限ループになります。ループを抜けるには break 文を使用します。

package main

import (
	"fmt"
	"time"
)

func main() {
	count := 0
	for { // 無限ループ
		fmt.Println("ループ中...")
		time.Sleep(500 * time.Millisecond)
		count++
		if count >= 3 {
			fmt.Println("ループを抜けます。")
			break // countが3以上になったらループを終了
		}
	}
}

ループ内の特定の回の残りの処理をスキップして次のイテレーションに進むには continue 文を使用します。

for range ループ ✨

スライス、配列、マップ、文字列、チャンネルなど、反復可能なデータ構造の要素を順番に取り出すのに便利です。

package main

import "fmt"

func main() {
	// スライスの例
	nums := []int{10, 20, 30}
	sum := 0
	// インデックス(i)と値(num)を取得
	for i, num := range nums {
		fmt.Printf("インデックス: %d, 値: %d\n", i, num)
		sum += num
	}
	fmt.Println("スライスの合計:", sum)

	// 値だけ必要な場合 (インデックスを無視)
	sum = 0
	for _, num := range nums { // インデックスを _ で破棄
		sum += num
	}
	fmt.Println("スライスの合計 (値のみ):", sum)


	// マップの例
	kvs := map[string]string{"a": "Apple", "b": "Banana"}
	// キー(k)と値(v)を取得
	for k, v := range kvs {
		fmt.Printf("%s -> %s\n", k, v)
	}

	// キーだけ必要な場合
	for k := range kvs {
		fmt.Println("キー:", k)
	}

	// 文字列の例 (rune単位で反復)
	for i, r := range "Go言語" {
		fmt.Printf("%d: %c\n", i, r) // iはバイト単位のインデックス, rはrune(文字)
	}
}
注意 (Go 1.22以降): 以前のGoバージョンでは、for rangeループ内で取得した変数はループ全体で同じメモリアドレスを指していましたが、Go 1.22からは各イテレーションで新しい変数が作られるように挙動が変更されました。これにより、ループ変数を使ったゴルーチンなどでの意図しないバグが起こりにくくなりました。初学者の段階では大きな影響はないかもしれませんが、知っておくと良いでしょう。

switch文:多岐分岐 🚦

switch文は、ある式の値に基づいて、複数の処理経路から一つを選んで実行します。if-else if を重ねるよりも簡潔に書ける場合があります。Goの switch は、一致した case の処理が終わると自動的に switch 文を抜けます(暗黙の break)。

基本的なswitch文

package main

import "fmt"

func main() {
	signal := "red"
	switch signal {
	case "red":
		fmt.Println("止まれ 🚦")
	case "yellow":
		fmt.Println("注意 ⚠️")
	case "blue", "green": // 複数の値をまとめることも可能
		fmt.Println("進め 👍")
	default: // どの case にも一致しない場合
		fmt.Println("不明な信号")
	}
}

fallthrough

Goでは通常、case の終わりに暗黙的な break がありますが、意図的に次の case の処理も実行したい場合は fallthrough キーワードを使用します。ただし、fallthrough の使用はコードを読みにくくすることがあるため、慎重に使いましょう。

package main

import "fmt"

func main() {
	num := 2
	switch num {
	case 1:
		fmt.Println("1")
		fallthrough // 次のcaseも実行
	case 2:
		fmt.Println("2") // ここが実行される
		fallthrough // さらに次のcaseも実行
	case 3:
		fmt.Println("3") // ここも実行される
	default:
		fmt.Println("default")
	}
	// 出力:
	// 2
	// 3
}

式なしswitch (switch true)

switch の後に式を書かない場合、switch true と同じ意味になり、各 case に書かれた条件式を上から順に評価し、最初に true になった case の処理を実行します。これは複雑な if-else if-else 文をよりきれいに書く方法として使えます。

package main

import "fmt"

func main() {
	score := 88
	switch { // 式を省略 (switch true と同じ)
	case score >= 90:
		fmt.Println("優")
	case score >= 80:
		fmt.Println("良") // ここが true になるので実行される
	case score >= 70:
		fmt.Println("可")
	default:
		fmt.Println("不可")
	}
}
ヒント: 式なし switch は、条件分岐が複数ある場合にコードを読みやすくするのに役立ちます。👍

まとめ

コメント

タイトルとURLをコピーしました