Go/条件分岐と繰り返し
制御構造
編集Go言語では、プログラムのフローを制御するためにいくつかの制御構造が用意されています。これらの構造は、プログラムのロジックを実行する際に重要な役割を果たします。本章では、Go言語における主な制御構造について説明します。
条件分岐
編集Goでは、条件分岐をif文などで行いますが、C言語とは異なります。C言語にもif、else、switchなどがありますが、スコープルールなどに違いがあります。
基本的なif文
編集package main import "fmt" func main() { number := 10 if number > 5 { fmt.Println("numberは5より大きい") } }
このコードでは、number
が5より大きいため、"numberは5より大きい"
が出力されます。
else文
編集package main import "fmt" func main() { number := 3 if number > 5 { fmt.Println("numberは5より大きい") } else { fmt.Println("numberは5以下") } }
このコードでは、number
が3なので、"numberは5以下"
が出力されます。
else if文
編集package main import "fmt" func main() { number := 7 if number > 10 { fmt.Println("numberは10より大きい") } else if number > 5 { fmt.Println("numberは5より大きく、10以下") } else { fmt.Println("numberは5以下") } }
このコードでは、number
が7なので、"numberは5より大きく、10以下"
が出力されます。
- コード例
package main import ( "fmt" "math" ) func main() { if num := math.NaN(); num < 0.0 { fmt.Println("負") } else if num > 0.0 { fmt.Println("正") } else if num == 0.0 { fmt.Println("零") } else { fmt.Println("NaN") } }
- 実行結果
NaN
Goでは、if文の条件式の前に「単純な文」を書くことが可能です。上記の例では、変数numがmath.NaN()で初期化されており、そのスコープはif文の中に限定されます。
switch文
編集switch文を使うと、複雑なif文を簡潔に表現できます。
- コード例
package main import ( "fmt" "math" ) func main() { switch num := math.NaN(); { case num < 0.0: fmt.Println("負") case num > 0.0: fmt.Println("正") case num == 0.0: fmt.Println("零") default: fmt.Println("NaN") } }
- 実行結果
NaN
Goのswitch文では、if文と同様に「単純な文」を書くことができます。C言語やJavaのようにbreak文は不要で、fallthrough文を使わない限り、自動的にcase節の終わりで処理が終了します。
型によるswitch
編集package main import "fmt" func main() { var x interface{} = "Hello" switch v := x.(type) { case int: fmt.Println("xはint型です") case string: fmt.Println("xはstring型です:", v) default: fmt.Println("xはその他の型です") } }
このコードでは、x
がstring
型であるため、"xはstring型です: Hello"
が出力されます。
select文
編集select文は、通信チャンネルを使った並行処理のための構文です。複数のチャンネルからの入力を待機し、その中で最初に準備ができたものを処理します。
- Select文を使ったタイムアウト
package main import ( "fmt" "time" ) func main() { done := make(chan bool) go func(s int) { fmt.Printf("#%d..do\n", s) time.Sleep(time.Duration(s) * time.Second) fmt.Printf("#%d..done\n", s) done <- true }(2) select { case <-done: fmt.Println("Done!") case <-time.After(1 * time.Second): fmt.Println("Timeout!") } }
- 実行結果
#2..do Timeout!
反復:for文
編集Goでは、for
文が唯一の繰り返し構文です。Goにはdo
やwhile
はなく、for文のみで繰り返し処理を行います。
Cスタイルの for
文 (初期化、条件式、後処理)
編集
Goでは、C言語のような構文で for
文を使用できます。この形式では、初期化、条件式、後処理を記述することができます。
package main import "fmt" func main() { for i := 0; i < 5; i++ { fmt.Println(i) } }
- 実行結果
0 1 2 3 4
この例では、i
を0から始めて5未満の間、1ずつ増加させながらループを繰り返します。i++
は後処理にあたります。
条件式だけの for
文
編集
for
文の初期化と後処理を省略し、条件式のみを使うこともできます。C言語のwhile
文に相当します。
package main import "fmt" func main() { i := 0 for i < 5 { fmt.Println(i) i++ } }
- 実行結果
0 1 2 3 4
ここでは、i
が5未満である限りループを繰り返します。i++
はループ内で更新されます。
無限ループ
編集条件式を省略すると、無限ループを作成することができます。break
を使ってループを終了させることができます。
package main import "fmt" func main() { for { fmt.Println("無限ループ") break // ループを終了 } fmt.Println("脱出") }
- 実行結果
無限ループ 脱出
このように、Goの for
文は非常に柔軟で、様々なループの形に対応しています。
range
を使ったループ
編集
Goでは、range
を使うことで、配列やスライス、マップ、チャンネルなどを簡単にループ処理できます。
- スライス
package main import "fmt" func main() { s := []int{2, 3, 5, 7, 11} for index, value := range s { fmt.Println(index, value) } }
- 実行結果
0 2 1 3 2 5 3 7 4 11
- マップ
package main import "fmt" func main() { m := map[string]int{"a": 1, "b": 2, "c": 3} for key, value := range m { fmt.Println(key, value) } }
- 実行結果
a 1 b 2 c 3
- チェンネル
package main import "fmt" func main() { ch := make(chan int) go func(ch chan int) { for i := 0; i < 5; i++ { ch <- 2*i + 1 } close(ch) }(ch) for num := range ch { fmt.Println(num) } fmt.Println("done.") }
- 実行結果
1 3 5 7 9 done.
rangeと関数を使ったループ
編集Go 1.23 では、for
文の range
構文が拡張され、関数を使ってイテレーションができるようになりました。これにより、配列やスライス、マップ、チャネルだけでなく、関数の結果を使ってループ処理を行うことが可能になりました。
具体的には、関数を引数として受け取り、その yield
を使って値を返し、for
文がその値を反復処理します。この仕組みによって、再帰的なデータ構造や動的に生成されるデータを簡単に扱えるようになりました。
- 例
package main import "fmt" func main() { factorial := func(yield func(x int) bool) { result := 1 i := 1 for yield(result) { result *= i i++ } } // print the factorial numbers below 1000: for x := range factorial { if x >= 1000 { break } fmt.Printf("%d ", x) } }
- 実行結果
1 1 2 6 24 120 720
このように、関数内で yield
を使って値を返し、for
文でその値を反復処理することができます。
まとめ
編集Go言語の制御構造は、プログラムのフローを柔軟に制御するための強力なツールです。条件分岐やループ、並行処理を適切に使い分けることで、効率的で読みやすいコードを書くことができます。