キーワード

Go言語のfor文の基本的な使い方について解説

この記事では、Go言語のforループに焦点をあて、シンプルで柔軟な繰り返し処理の使い方について解説します。

基本的な構文と実例を通して、直感的に理解しやすいループ処理のパターンを紹介します。

基本的なfor文の構文

初期化・条件・後処理の記述方法

Goのfor文は、初期化、条件、後処理の3つの要素をセミコロンで区切って記述する形式が一般的です。

例えば、変数を初期化して、条件が真である間ループし、後処理として変数を更新する場合は、以下のように書きます。

package main
import "fmt"
func main() {
	// 変数iを0で初期化し、iが5未満の場合にループ、
	// ループ終了後にiをインクリメントする
	for i := 0; i < 5; i++ {
		fmt.Println("カウンタ:", i) // カウンタの値を表示
	}
}
カウンタ: 0
カウンタ: 1
カウンタ: 2
カウンタ: 3
カウンタ: 4

この形式は、数式i=0,i<5,i++という形で記述され、ループの開始、継続条件、終了処理が一目で把握できます。

シンプルなループ処理の書き方

for文は、シンプルなループ処理のためにも利用できます。

ループ変数や後処理が不要な場合でも、1行でループの条件を書くことが可能です。

例えば、単純に条件に合致する間だけループさせるケースを示します。

package main
import "fmt"
func main() {
	counter := 0
	// 条件のみを記述したfor文でカウンタが3未満の間ループ
	for counter < 3 {
		fmt.Println("シンプルループ:", counter)
		counter++ // カウンタを明示的に更新
	}
}
シンプルループ: 0
シンプルループ: 1
シンプルループ: 2

このように、初期化や後処理を外部で行い、条件だけをfor文に記述することで柔軟なループが実現できます。

多様なfor文の利用方法

条件式のみを用いるループ(while文風)

Goではwhile文が存在しないため、条件式のみを使ったfor文で同様の処理を実現します。

条件が真である限りループを継続するため、以下の例のように使用します。

package main
import "fmt"
func main() {
	// counterの初期化
	counter := 0
	// 条件のみのfor文はwhile文と同じ動作をします
	for counter < 4 {
		fmt.Println("条件式のみループ:", counter)
		counter++ // カウンタを更新して条件に影響させる
	}
}
条件式のみループ: 0
条件式のみループ: 1
条件式のみループ: 2
条件式のみループ: 3

条件を満たさなくなればループは終了するため、while文と同様に扱えます。

無限ループの実現(for{}の活用法)

初期化や条件、後処理を一切記述しないfor文は無限ループを実現するために使用します。

必要なタイミングでbreak文を用いてループを抜けることで、柔軟にループ処理を構成できます。

package main
import "fmt"
func main() {
	counter := 0
	// 無限ループの開始
	for {
		// 必要な処理を実行
		fmt.Println("無限ループ:", counter)
		counter++
		// counterが5になったらループを終了する
		if counter >= 5 {
			break // ループ終了
		}
	}
}
無限ループ: 0
無限ループ: 1
無限ループ: 2
無限ループ: 3
無限ループ: 4

必要なときにbreak文を使用することで、無限ループの中で適切に処理を抜けられます。

実践的な反復処理例

スライス・配列の反復処理

Goでは、スライスや配列の各要素に対してfor文を使って反復処理が可能です。

代表的な方法はrangeキーワードを使う方法で、インデックスと値を簡単に取得できます。

package main
import "fmt"
func main() {
	// 数値を格納するスライスを定義
	numbers := []int{10, 20, 30, 40, 50}
	// スライスの各要素を反復処理
	for index, value := range numbers {
		fmt.Printf("インデックス: %d, 値: %d\n", index, value)
	}
}
インデックス: 0, 値: 10
インデックス: 1, 値: 20
インデックス: 2, 値: 30
インデックス: 3, 値: 40
インデックス: 4, 値: 50

この方法は配列にも同様に適用でき、可読性の高いコードが作成可能です。

Mapでのキーと値の取得

rangeキーワードは、Map型の反復処理にも利用できます。

Mapの各要素に対してキーと値を取得する例を示します。

package main
import "fmt"
func main() {
	// 文字列をキー、整数を値としたMapを定義
	scoreMap := map[string]int{
		"alice": 85,
		"bob":   90,
		"carol": 78,
	}
	// Mapのキーと値を反復処理
	for key, value := range scoreMap {
		fmt.Printf("名前: %s, スコア: %d\n", key, value)
	}
}
名前: alice, スコア: 85
名前: bob, スコア: 90
名前: carol, スコア: 78

Mapの場合、要素の順序は保証されない点に注意してください。

rangeキーワードによる反復

rangeキーワードは、スライス、配列、Mapだけでなく、文字列やチャネルに対しても使用できます。

ここでは、文字列中の各文字(ルーン)を反復処理する例を示します。

package main
import "fmt"
func main() {
	message := "こんにちは"
	// 文字列中の各ルーンを反復処理
	for index, char := range message {
		fmt.Printf("位置: %d, 文字: %c\n", index, char)
	}
}
位置: 0, 文字: こ
位置: 3, 文字: ん
位置: 6, 文字: に
位置: 9, 文字: ち
位置: 12, 文字: は

文字列のルーンごとの反復処理により、UTF-8対応の柔軟な実装が可能です。

ループ制御と注意点

breakとcontinueの使い分け

ループ中の特定の条件で処理を中断したり、次の反復処理に移る場合に、breakcontinueを使用できます。

以下の例では、条件に合致する場合にcontinueでスキップし、別の条件でbreakを用いてループを終了しています。

package main
import "fmt"
func main() {
	// 0から9までループ
	for i := 0; i < 10; i++ {
		// もしiが偶数の場合は、スキップする
		if i%2 == 0 {
			continue
		}
		// iが7になったらループを終了する
		if i == 7 {
			break
		}
		fmt.Println("ループ制御:", i)
	}
}
ループ制御: 1
ループ制御: 3
ループ制御: 5

このように、continueは現在の反復を終了して次に進み、breakはループ全体を終了します。

ネストされたループでの適用

ネストされたループの場合、breakcontinueは内側のループに対して作用します。

外側のループも同時に終了させたい場合、ラベルを付けて指定する方法があります。

package main
import "fmt"
func main() {
	// 外側のループにラベルを付ける
OuterLoop:
	for i := 1; i <= 3; i++ {
		for j := 1; j <= 3; j++ {
			// 特定の条件で外側のループも終了する
			if i*j > 4 {
				break OuterLoop // 外側のループ全体を抜ける
			}
			fmt.Printf("i: %d, j: %d\n", i, j)
		}
	}
}
i: 1, j: 1
i: 1, j: 2
i: 1, j: 3
i: 2, j: 1

ラベルを用いると、対象のループを明確に指定でき、意図しないループ継続を防ぐことができます。

ループ変数のスコープと再代入時の留意点

ループ変数はfor文のブロック内で有効です。

そのため、ループ外で同名の変数を使用しても問題ありません。

また、ループ変数が予期せず上書きされないように、変数のスコープに注意する必要があります。

使い方の例として、for文内でループ変数をそのまま別のゴルーチンに渡す際の注意点を示します。

package main
import (
	"fmt"
	"time"
)
func main() {
	// クロージャでループ変数を捕捉する際に意図した値として使うためには、
	// 変数をローカルコピーすると安全です
	for i := 0; i < 3; i++ {
		// 変数コピーを行う
		value := i
		go func() {
			// valueを使って出力
			time.Sleep(10 * time.Millisecond)
			fmt.Println("ゴルーチン内の値:", value)
		}()
	}
	// 十分な待ち時間を設ける
	time.Sleep(50 * time.Millisecond)
}
ゴルーチン内の値: 0
ゴルーチン内の値: 1
ゴルーチン内の値: 2

ループ変数の再代入やクロージャへの渡し方に注意することで、意図しない動作を防ぐことができます。

まとめ

この記事では、Go言語のfor文の基本的な構文と応用例、ならびにループ制御の注意点について詳しく解説しました。

各サンプルコードと具体例によって、for文の使い方が明確に理解できる内容となっています。

ぜひ実際にコードを動かしながら、学習を進めてみてください。

関連記事

Back to top button
目次へ