前書き

https://www.digitalocean.com/community/tutorials/how-to-write-conditional-statements-in-go [条件文]は、条件が真である場合と他の条件が真である場合に、何らかのアクションをとるようにプログラムに指示する機能をプログラマに提供します。条件が偽の場合のアクション。 多くの場合、いくつかのhttps://www.digitalocean.com/community/tutorials/how-to-use-variables-and-constants-in-go#understanding-variables[variable]を複数の可能な値と比較し、各状況でのアクション。 https://www.digitalocean.com/community/tutorials/how-to-write-conditional-statements-in-go#if-statements [`+ if `ステートメント]のみを使用して、この作業を行うことができます。 ただし、ソフトウェアを書くことは、物事を機能させるだけでなく、自分の意思を将来の自分や他の開発者に伝えることでもあります。 ` 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 +`内で、アイスクリームフレーバーのhttps://www.digitalocean.com/community/tutorials/understanding-data-types-in-go#slices [スライス]を定義します。 次に、https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-go [+ for loop `]を使用してそれらを繰り返し処理します。 3つの「 if」ステートメントを使用して、さまざまなアイスクリームフレーバーの設定を示すさまざまなメッセージを出力します。 各「+ if 」ステートメントは「 continue」ステートメントを使用して「+ for」ループの実行を停止する必要があります。これにより、最後のデフォルトのメッセージが好みのアイスクリームフレーバーに対して出力されません。

新しいアイスクリームの設定を追加するとき、新しいケースを処理するために `+ if `ステートメントを追加し続ける必要があります。 `” vanilla “`および `” chocolate “`の場合のように、重複したメッセージには、重複した ` if `ステートメントが必要です。 コードの将来の読者(私たち自身も含む)にとって、 ` if `ステートメントの反復的な性質は、変数の複数の値との比較と異なるアクションの実行の重要な部分を曖昧にします。 また、フォールバックメッセージは条件とは別に設定されているため、無関係に見えます。 ` switch +`ステートメントは、このロジックをよりよく整理するのに役立ちます。

+ switch +`ステートメントは `+ switch +`キーワードで始まり、最も基本的な形式で、比較を実行するための変数が続きます。 これには、複数の_case節_が現れることができる中括弧( `+ {} +)のペアが続きます。 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 `句はcatch-all句として機能します。 これは、 ` switch `ステートメントの本文で説明していないフレーバーに対して実行されます。 この場合、 `” banana “`により ` default `が実行され、 ` I’ve never never banana +`というメッセージが出力されます。

`+ 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`を使用して、現在の時刻に基づいて乱数ジェネレーターをランダム化します。 `+ rand.Intn `の引数 ` 100 `は、0〜100の範囲の数値を提供します。 次に、「 for」ループを使用して、プレーヤーからの推測の収集を開始します。

`+ fmt.Scanf `関数は、ユーザーの入力を選択した変数に読み込む手段を提供します。 それは、ユーザーの入力を期待するタイプに変換するフォーマット文字列動詞を取ります。 ここでの「%d 」は、「 int 」が必要であることを意味し、「 fmt.Scanf 」がその変数を設定できるように、「 guess 」変数のアドレスを渡します。 https://www.digitalocean.com/community/tutorials/handling-errors-in-go [解析エラーの処理]の後、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 + に置き換えたのと同様に、 + case + 句が1つだけ実行されるため、 + 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!+`が出力されます。

Go開発者は、「+ fallthrough 」キーワードをあまり使用しません。 通常、 ` fallthrough `を使用して実現されるコードの再利用は、共通のコードを使用して関数を定義することで得られます。 これらの理由から、 ` fallthrough +`の使用は一般的に推奨されません。

結論

`+ switch `ステートメントは、コードを読んでいる他の開発者に、一連の比較が何らかの形で互いに関連していることを伝えるのに役立ちます。 将来新しいケースが追加されたときに異なる動作を追加するのがはるかに簡単になり、忘れたものはすべて ` default `句で適切に処理されるようになります。 次回、同じ変数をすべて含む複数の ` if `ステートメントを記述した場合は、 ` switch +`ステートメントで書き直してみてください。他の代替値を検討するときに、作業しやすくなります。

Goプログラミング言語について詳しく知りたい場合は、https://www.digitalocean.com/community/tutorial_series/how-to-code-in-go [Goシリーズのコーディング方法]全体をご覧ください。