switch ステートメントを使用する制御フロー
他のプログラミング言語と同様に、Go では switch
ステートメントがサポートされています。 switch
ステートメントは、複数の if
ステートメントをつなげるのを避けるために使用します。 多くの if
ステートメントが含まれるコードを保守したり読んだりするのは困難ですが、switch
ステートメントを使用するとそれがなくなります。 また、これらのステートメントを使用すると、複雑な条件を簡単に作成できるようになります。 以下のセクションでは switch
ステートメントを見ていきましょう。
switch の基本的な構文
if
ステートメントと同様に、switch
の条件にかっこは必要ありません。 switch
ステートメントの最も単純な形式は次のようになります。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
sec := time.Now().Unix()
rand.Seed(sec)
i := rand.Int31n(10)
switch i {
case 0:
fmt.Print("zero...")
case 1:
fmt.Print("one...")
case 2:
fmt.Print("two...")
}
fmt.Println("ok")
}
上記のコードを複数回実行すると、毎回異なる出力が表示されます。 (ただし、Go Playground でコードを実行すると、毎回同じ結果が得られます。これは、サービスの制限事項の 1 つです)
Go では、一致する条件が見つかるまで、switch
ステートメントの各ケースが比較されます。 ただし、前のコードでは、num
変数で可能性のあるすべての値のケースがカバーされていないことに注意してください。 num
が最終的に 5
になる場合、プログラムの出力は ok
になります。
また、既定のユース ケースをより具体的に示し、次のように指定することもできます。
switch i {
case 0:
fmt.Print("zero...")
case 1:
fmt.Print("one...")
case 2:
fmt.Print("two...")
default:
fmt.Print("no match...")
}
default
ケースの場合、検証式を記述しないことに注意してください。 i
変数の値の有効性が case
ステートメントに照らして検証され、検証されない値が default
ケースによって処理されます。
複数の式を使用する
複数の式がただ 1 つの case
ステートメントと一致する場合があります。 Go では、case
ステートメントに複数の式を含めたい場合は、コンマ (,
) を使用して式を区切ります。 この手法により、コードの重複を防ぐことができます。
次のコード サンプルでは、複数の式を含める方法を示します。
package main
import "fmt"
func location(city string) (string, string) {
var region string
var continent string
switch city {
case "Delhi", "Hyderabad", "Mumbai", "Chennai", "Kochi":
region, continent = "India", "Asia"
case "Lafayette", "Louisville", "Boulder":
region, continent = "Colorado", "USA"
case "Irvine", "Los Angeles", "San Diego":
region, continent = "California", "USA"
default:
region, continent = "Unknown", "Unknown"
}
return region, continent
}
func main() {
region, continent := location("Irvine")
fmt.Printf("John works in %s, %s\n", region, continent)
}
case
ステートメントの式に含める値は、switch
ステートメントで検証する変数のデータ型に対応していることに注意してください。 新しい case
ステートメントとして整数値を指定した場合、プログラムはコンパイルされません。
関数の呼び出し
switch
で関数を呼び出すこともできます。 その関数からの考えられる戻り値に対する case
ステートメントを記述できます。 たとえば、次のコードでは、time.Now()
関数を呼び出しています。 表示される出力は、現在の曜日によって異なります。
package main
import (
"fmt"
"time"
)
func main() {
switch time.Now().Weekday().String() {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
fmt.Println("It's time to learn some Go.")
default:
fmt.Println("It's the weekend, time to rest!")
}
fmt.Println(time.Now().Weekday().String())
}
switch
ステートメントから関数を呼び出すと、関数から返される内容が常に検証されるため、式を変更せずにそのロジックを変更できます。
また、case
ステートメントから関数を呼び出すこともできます。 たとえば、正規表現を使用して特定のパターンに一致させるには、この方法を使用します。 次に例を示します。
package main
import "fmt"
import "regexp"
func main() {
var email = regexp.MustCompile(`^[^@]+@[^@.]+\.[^@.]+`)
var phone = regexp.MustCompile(`^[(]?[0-9][0-9][0-9][). \-]*[0-9][0-9][0-9][.\-]?[0-9][0-9][0-9][0-9]`)
contact := "foo@bar.com"
switch {
case email.MatchString(contact):
fmt.Println(contact, "is an email")
case phone.MatchString(contact):
fmt.Println(contact, "is a phone number")
default:
fmt.Println(contact, "is not recognized")
}
}
switch
ブロックに検証式がないことに注意してください。 その概念については、次のセクションで説明します。
条件を省略する
Go では、if
ステートメントの場合と同様に、switch
ステートメントで条件を省略できます。 このパターンは、switch
ステートメントを常に実行するように、true
値と比較するのと似ています。
条件のない switch
ステートメントを記述する方法の例を次に示します。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().Unix())
r := rand.Float64()
switch {
case r > 0.1:
fmt.Println("Common case, 90% of the time")
default:
fmt.Println("10% of the time")
}
}
条件は常に true なので、この種の switch
ステートメントはプログラムで常に実行されます。 条件付き switch
ブロックの方が、if
ステートメントと else if
ステートメントの長いチェーンよりメンテナンスが簡単な場合があります。
ロジックが次の case にフォールスルーされるようにする
一部のプログラミング言語では、すべての case
ステートメントの最後に break
キーワードを記述します。 しかし Go の場合は、ロジックが 1 つの case に分岐すると、明示的に停止しない限り、switch
ブロックは終了します。 ロジックがすぐ次の case にフォールスルーされるようにするには、fallthrough
キーワードを使用します。
このパターンをもっとよく理解するには、次のコード サンプルを見てください。
package main
import (
"fmt"
)
func main() {
switch num := 15; {
case num < 50:
fmt.Printf("%d is less than 50\n", num)
fallthrough
case num > 100:
fmt.Printf("%d is greater than 100\n", num)
fallthrough
case num < 200:
fmt.Printf("%d is less than 200", num)
}
}
コードを実行し、出力を分析します。
15 is less than 50
15 is greater than 100
15 is less than 200
何が間違っているかわかりますか。
num
は 15 (50 未満) なので、最初の case と一致します。 しかし、num
は 100 より大きくはありません。 また、最初の case
ステートメントには fallthrough
キーワードがあるため、ロジックは case を検証せずに次の case
ステートメントに直ちに移動します。 したがって、fallthrough
キーワードを使用する場合は注意が必要です。 このコードによって望まない動作が作成される可能性があります。