前書き
Conditional statementsは、条件が真の場合は何らかのアクションを実行し、条件が偽の場合は別のアクションを実行するようにプログラムに指示する機能をプログラマーに提供します。 多くの場合、いくつかのvariableを複数の可能な値と比較し、状況ごとに異なるアクションを実行します。 if
statementsのみを使用してこの作業を行うことができます。 ただし、ソフトウェアを書くことは、物事を機能させるだけでなく、自分の意思を将来の自分や他の開発者に伝えることでもあります。 switch
は、さまざまなオプションが提示されたときにGoプログラムによって実行されるアクションを伝達するのに役立つ代替の条件ステートメントです。
switchステートメントで記述できるものはすべて、if
ステートメントでも記述できます。 このチュートリアルでは、switchステートメントで実行できること、置き換えられるif
ステートメント、および最も適切に適用される場所の例をいくつか見ていきます。
Switchステートメントの構造
スイッチは一般に、変数に特定の値が割り当てられたときにプログラムが実行するアクションを記述するために使用されます。 次の例は、if
ステートメントを使用してこれを実現する方法を示しています。
package main
import "fmt"
func main() {
flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
for _, flav := range flavors {
if flav == "strawberry" {
fmt.Println(flav, "is my favorite!")
continue
}
if flav == "vanilla" {
fmt.Println(flav, "is great!")
continue
}
if flav == "chocolate" {
fmt.Println(flav, "is great!")
continue
}
fmt.Println("I've never tried", flav, "before")
}
}
これにより、次の出力が生成されます。
Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before
main
内で、アイスクリームフレーバーのsliceを定義します。 次に、for loop
を使用してそれらを反復処理します。 3つのif
ステートメントを使用して、さまざまなアイスクリームフレーバーの好みを示すさまざまなメッセージを出力します。 各if
ステートメントはcontinue
ステートメントを使用してfor
ループの実行を停止し、最後のデフォルトメッセージが優先アイスクリームフレーバーに対して出力されないようにする必要があります。
新しいアイスクリームの設定を追加するときは、新しいケースを処理するためにif
ステートメントを追加し続ける必要があります。 "vanilla"
および"chocolate"
の場合のように、重複したメッセージには、重複したif
ステートメントが含まれている必要があります。 私たちのコードの将来の読者(私たち自身を含む)にとって、if
ステートメントの反復的な性質は、変数を複数の値と比較し、異なるアクションを実行するという、彼らが行っていることの重要な部分を覆い隠します。 また、フォールバックメッセージは条件とは別に設定されているため、無関係に見えます。 switch
ステートメントは、このロジックをより適切に編成するのに役立ちます。
switch
ステートメントは、switch
キーワードで始まり、最も基本的な形式で、比較を実行するための変数が続きます。 この後に、複数のcase clausesが表示される可能性のある1組の中括弧({}
)が続きます。 case句は、switch文に提供された変数がcase句によって参照される値と等しい場合にGoプログラムが実行するアクションを記述します。 次の例は、前の例を変換して、複数のif
ステートメントの代わりにswitch
を使用します。
package main
import "fmt"
func main() {
flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
for _, flav := range flavors {
switch flav {
case "strawberry":
fmt.Println(flav, "is my favorite!")
case "vanilla", "chocolate":
fmt.Println(flav, "is great!")
default:
fmt.Println("I've never tried", flav, "before")
}
}
}
出力は以前と同じです。
Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before
もう一度、アイスクリームフレーバーのスライスをmain
で定義し、range
ステートメントを使用して各フレーバーを反復処理しました。 ただし、今回は、flav
変数を調べるswitch
ステートメントを使用しました。 設定を示すために2つのcase
句を使用します。 switch
ステートメントによって実行されるcase
句は1つだけなので、continue
ステートメントは不要になりました。 case
句の宣言でそれぞれをコンマで区切ることにより、"chocolate"
条件と"vanilla"
条件の重複したロジックを組み合わせることができます。 default
句は、キャッチオール句として機能します。 switch
ステートメントの本文で説明されていないすべてのフレーバーに対して実行されます。 この場合、"banana"
によってdefault
が実行され、メッセージI've never tried banana before
が出力されます。
この簡略化された形式のswitch
ステートメントは、変数を複数の選択肢と比較するという、それらの最も一般的な使用法に対応しています。 また、提供されたdefault
キーワードを使用して、リストされた条件のいずれも満たされない場合に、複数の異なる値に対して同じアクションを実行したり、他のアクションを実行したりする場合にも便利です。
この簡略化された形式のswitch
が制限しすぎることが判明した場合は、より一般的な形式のswitch
ステートメントを使用できます。
一般的なSwitchステートメント
switch
ステートメントは、より複雑な条件のコレクションをグループ化して、それらが何らかの形で関連していることを示すのに役立ちます。 これは、前の例のように特定の値ではなく、変数を値の範囲と比較するときに最も一般的に使用されます。 次の例では、switch
ステートメントの恩恵を受ける可能性のあるif
ステートメントを使用して推測ゲームを実装しています。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
target := rand.Intn(100)
for {
var guess int
fmt.Print("Enter a guess: ")
_, err := fmt.Scanf("%d", &guess)
if err != nil {
fmt.Println("Invalid guess: err:", err)
continue
}
if guess > target {
fmt.Println("Too high!")
continue
}
if guess < target {
fmt.Println("Too low!")
continue
}
fmt.Println("You win!")
break
}
}
出力は、選択した乱数とゲームのプレイ方法によって異なります。 次に、1つのセッション例の出力を示します。
OutputEnter a guess: 10
Too low!
Enter a guess: 15
Too low!
Enter a guess: 18
Too high!
Enter a guess: 17
You win!
推測ゲームでは、推測を比較するために乱数が必要なので、math/rand
パッケージのrand.Intn
関数を使用します。 ゲームをプレイするたびにtarget
の値が異なることを確認するために、rand.Seed
を使用して、現在の時刻に基づいて乱数ジェネレーターをランダム化します。 引数100
からrand.Intn
は、0〜100の範囲の数値を示します。 次に、for
ループを使用して、プレーヤーからの推測の収集を開始します。
fmt.Scanf
関数は、ユーザー入力を選択した変数に読み込む手段を提供します。 それは、ユーザーの入力を期待するタイプに変換するフォーマット文字列動詞を取ります。 ここでの%d
は、int
が必要であることを意味し、fmt.Scanf
がその変数を設定できるように、guess
変数のアドレスを渡します。 handling any parsing errorsの後、2つのif
ステートメントを使用して、ユーザーの推測をtarget
値と比較します。 返されるstring
は、bool
とともに、プレーヤーに表示されるメッセージと、ゲームを終了するかどうかを制御します。
これらのif
ステートメントは、変数が比較されている値の範囲がすべて何らかの方法で関連しているという事実をあいまいにします。 また、範囲の一部を逃したかどうかを一目で判断することは困難です。 次の例では、前の例をリファクタリングして、代わりにswitch
ステートメントを使用します。
package main
import (
"fmt"
"math/rand"
)
func main() {
target := rand.Intn(100)
for {
var guess int
fmt.Print("Enter a guess: ")
_, err := fmt.Scanf("%d", &guess)
if err != nil {
fmt.Println("Invalid guess: err:", err)
continue
}
switch {
case guess > target:
fmt.Println("Too high!")
case guess < target:
fmt.Println("Too low!")
default:
fmt.Println("You win!")
return
}
}
}
これにより、次のような出力が生成されます。
OutputEnter a guess: 25
Too low!
Enter a guess: 28
Too high!
Enter a guess: 27
You win!
このバージョンの推測ゲームでは、if
ステートメントのブロックをswitch
ステートメントに置き換えました。 switch
を使用して条件をまとめることにのみ関心があるため、switch
の式の引数は省略します。 各case
句には、guess
とtarget
を比較する異なる式が含まれています。 初めてif
ステートメントをswitch
に置き換えたときと同様に、1つのcase
句のみが実行されるため、continue
ステートメントは不要になりました。 最後に、default
句は、他の2つのcase
句で他のすべての可能な値をカバーしたため、guess == target
の場合を処理します。
これまで見てきた例では、正確に1つのcaseステートメントが実行されます。 場合によっては、複数のcase
句の動作を組み合わせたいことがあります。 switch
ステートメントは、この動作を実現するための別のキーワードを提供します。
フォールスルー
別のcase
句に含まれているコードを再利用したい場合があります。 このような場合、fallthrough
キーワードを使用して、リストされている次のcase
句の本文を実行するようにGoに要求することができます。 次の例では、以前のアイスクリームフレーバーの例を修正して、ストロベリーアイスクリームへの熱意をより正確に反映します。
package main
import "fmt"
func main() {
flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
for _, flav := range flavors {
switch flav {
case "strawberry":
fmt.Println(flav, "is my favorite!")
fallthrough
case "vanilla", "chocolate":
fmt.Println(flav, "is great!")
default:
fmt.Println("I've never tried", flav, "before")
}
}
}
次の出力が表示されます。
Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
strawberry is great!
I've never tried banana before
前に見たように、フレーバーを表すためにstring
のスライスを定義し、for
ループを使用してこれを繰り返します。 ここでのswitch
ステートメントは、前に見たものと同じですが、"strawberry"
のcase
句の最後にfallthrough
キーワードが追加されています。 これにより、Goはcase "strawberry":
の本体を実行し、最初に文字列strawberry is my favorite!
を出力します。 fallthrough
に遭遇すると、次のcase
句の本体を実行します。 これにより、case "vanilla", "chocolate":
の本体が実行され、strawberry is great!
が出力されます。
fallthrough
キーワードは、Go開発者によって頻繁に使用されることはありません。 通常、fallthrough
を使用して実現されるコードの再利用は、共通のコードで関数を定義することでより適切に取得できます。 これらの理由から、fallthrough
の使用は一般的に推奨されていません。
結論
switch
ステートメントは、コードを読んでいる他の開発者に、一連の比較が何らかの形で相互に関連していることを伝えるのに役立ちます。 これらは、将来新しいケースが追加されたときに異なる動作を追加することをはるかに簡単にし、忘れたものはすべてdefault
句で適切に処理されることを保証することを可能にします。 次回、すべて同じ変数を含む複数のif
ステートメントを記述していることに気付いたときは、switch
ステートメントで書き直してみてください。他の代替案を検討するときに、やり直しが簡単になります。値。
Goプログラミング言語について詳しく知りたい場合は、How To Code in Go series全体を確認してください。