Go言語でプログラミングをしていると、「もし、この数字だったらこの処理」「もし、あの文字列だったらあの処理」みたいに、色々な条件で処理を分けたい時ってありますよね。
そんな時に登場するのが、今回の主役 `switch` 文です!
`switch` 文は、たくさんの条件分岐を、もっとスッキリ、もっと分かりやすく書くための仕組みなんです。
例えるなら、たくさんのドア(条件)があって、持っている鍵(値)にピッタリ合うドアだけが開いて、その中の部屋(処理)に入れる、みたいなイメージでしょうか。
特にGo言語の `switch` 文は、他のプログラミング言語と少し違う特徴もあって、例えば、条件に一致した処理が終わったら自動的に `switch` 文全体が終了するんです。(他の言語だと、自分で「ここで終わり!」って書かないと、次の条件の処理に進んじゃうこともあるんですよ。)
このおかげで、書き忘れによる予期せぬ動きが減って、より安全にコードを書けるようになっています。
そんな便利な `switch` 文の世界を覗いてみましょう!
Go言語「switch文」の基本的な書き方
まずは `switch` 文がどんな形をしているのか、基本の構造を見てみましょう。
一番シンプルな形はこんな感じです。
switch 評価したい値や式 { case 値1: // 値1に一致した場合の処理 case 値2: // 値2に一致した場合の処理 case 値3, 値4: // カンマ区切りで複数の値も指定できる! // 値3 または 値4 に一致した場合の処理 default: // どのcaseにも一致しなかった場合の処理 }
それぞれの部分が何をしているか、簡単に説明しますね。
- switch 評価したい値や式
ここで条件分岐の基準になる値や、結果が値になる式を書きます。この値(式の結果)が、下の `case` の値と比較されます。 - case 値:
`switch` の後ろに書いた値(式の結果)が、この `case` の後ろに書いた「値」と一致するかどうかをチェックします。一致したら、コロン `:` の後の処理が実行されます。 - default:
どの `case` の値にも一致しなかった場合に、この `default` の後の処理が実行されます。いわば「それ以外の場合」担当です。これは省略することも可能です。
基本の形は意外とシンプルでしょう?
次は、それぞれの要素について、もう少し詳しく見ていきましょう。
case節:条件に一致した場合の処理
`case` は、`switch` 文の「もし〜だったら」の部分を担当します。
`switch` の後ろに書いた値(や式の結果)と、`case` の後ろに書いた値がピッタリ一致したら、その `case` に書かれた処理が実行される仕組みです。
例えば、`switch num` と書いて、変数 `num` の中身が `10` だった場合、`case 10:` と書かれた部分の処理が動きます。
一つの `case` で複数の値をチェックしたい場合は、下のようにカンマ `,` で区切って書くこともできますよ。
case 1, 3, 5: // 奇数だったらここの処理 case 2, 4, 6: // 偶数だったらここの処理
ここで大事なのは、switchの後ろにある式の『結果』とcaseの後ろにある『値』が同じ種類(型)であることです。数値なら数値、文字列なら文字列と、ちゃんと合わせてあげてくださいね。
default節:どの条件にも一致しなかった場合の処理
`default` 節は、用意したどの `case` にも当てはまらなかった場合の「最終手段」あるいは「保険」のようなものです。
`if` 文で言うところの `else` に似ていますね。
全ての `case` をチェックしても一致するものがなかった時に、この `default` に書かれた処理が実行されます。
`default` は必ず書かないといけないわけではなく、省略することも可能です。もし省略して、どの `case` にも一致しなかった場合は、`switch` 文の中の処理は何も実行されずに終わります。
書く場合は、一般的に `switch` 文の一番最後に書くことが多いです。
defaultは必須ではありませんが、想定外の値が入ってきた場合に備えて書いておくと、プログラムがより親切になるかもしれませんね。例えば「入力が正しくありません」のようなメッセージを出す、といった使い方ができます。
Go言語「switch」文の使い方
さあ、いよいよ実際に `switch` 文を使ったコードを見てみましょう!
百聞は一見にしかず、動くコードを見るのが一番分かりやすいですからね。
ここでは、おみくじの結果を数字で受け取って、その数字に応じたメッセージを表示する、という簡単な例を考えてみます。
サンプルプログラムと実行結果
まずは、プログラム全体と、それを実行した結果をお見せします。
お手元にGo言語の実行環境がある方は、ぜひコピーして動かしてみてください!
package main import "fmt" func main() { // おみくじの結果(1が大吉, 2が中吉, 3が小吉, それ以外は末吉) omikujiResult := 1 fmt.Println("おみくじの結果は...") switch omikujiResult { case 1: fmt.Println("大吉!やったね!") case 2: fmt.Println("中吉!いい感じ!") case 3: fmt.Println("小吉!まあまあかな!") default: fmt.Println("末吉!次こそは!") } fmt.Println("-----") // 文字列でも試してみよう signal := "red" fmt.Println("信号の色は...") switch signal { case "blue", "green": // 青信号と緑信号は同じ扱い fmt.Println("進め!") case "yellow": fmt.Println("注意!") case "red": fmt.Println("止まれ!") default: fmt.Println("???") } }
実行結果
おみくじの結果は... 大吉!やったね! ----- 信号の色は... 止まれ!
どうでしょう? `if-else if` をたくさん書くよりも、なんだかスッキリして見えませんか?
まずはコピーして、お手元の環境で動かしてみるのが一番です! `omikujiResult` や `signal` の値を変えてみると、表示されるメッセージが変わるのが確認できるはずですよ。
サンプルプログラムの解説
上のサンプルコードが何をやっているか、順番に見ていきましょう。
- おみくじの例:
- まず、`omikujiResult` という変数に `1` を入れています。
- `switch omikujiResult { ... }` で、この変数の値をチェックし始めます。
- `case 1:` が変数の中身 `1` と一致したので、`fmt.Println("大吉!やったね!")` が実行されます。
- Goの `switch` 文は、一致したcaseの処理が終わったら自動でswitch文を抜けるので、`case 2:` や `case 3:`、`default:` はチェックされずに `switch` 文が終了します。便利!
- 信号機の例:
- `signal` という変数に文字列 `"red"` を入れています。
- `switch signal { ... }` で、この変数の値をチェックします。
- `case "blue", "green":` は `"red"` と一致しません。
- `case "yellow":` も `"red"` と一致しません。
- `case "red":` が変数の中身 `"red"` と一致したので、`fmt.Println("止まれ!")` が実行されます。
- ここで `switch` 文は終了します。
こんな風に、`switch` 文は変数の値に応じて、実行する処理を振り分けてくれるんですね。
数値だけでなく、文字列も同じように使えるのが分かったかと思います。
Go言語「switch文」の便利な使い方
基本的な使い方が分かったところで、次はGo言語の `switch` 文が持つ、もう少し応用的な機能を見ていきましょう。
これらを知っていると、さらにコードをスッキリさせたり、特定の状況で便利な処理が書けたりしますよ。
「へぇ、`switch` 文ってこんなこともできるんだ!」と、きっと思ってもらえるはずです。
式を使わないswitch文(if-else ifの代替)
実は `switch` 文、`switch` の直後に評価する値や式を書かなくても使えるんです。
こんな書き方をします。
score := 75 switch { // switchの後ろに何もない! case score >= 90: fmt.Println("優") case score >= 70: fmt.Println("良") case score >= 50: fmt.Println("可") default: fmt.Println("不可") } // 実行結果: 良
`switch` の後ろに何も書かない場合、Go言語は `switch true` と書かれたものとして扱います。
そして、各 `case` の後ろに書かれた「条件式」を上から順番に評価していき、最初に `true` (真) になった `case` の処理を実行して `switch` 文を抜けます。
これ、何かに似ていませんか?
そう、`if-else if-else` の構造とそっくりなんです!
比べてみると…
// if-else if の場合 if score >= 90 { fmt.Println("優") } else if score >= 70 { fmt.Println("良") } else if score >= 50 { fmt.Println("可") } else { fmt.Println("不可") }
`switch {}` を使った方が、少しだけスッキリ書ける場合もありますね。
条件式をcaseに直接書けるので、複雑な条件分岐も比較的読みやすく記述できることがあります。どちらを使うかは好みや状況によりますが、こんな書き方もあるんだと覚えておくと便利です。
fallthroughキーワード:次のcaseも実行する
Go言語の `switch` 文の大きな特徴として、「一致した `case` の処理が終わったら、自動的に `switch` 文全体から抜ける(暗黙の `break`)」という点がありましたね。
でも、場合によっては、「この `case` の処理が終わった後、あえて次の `case` の処理も続けて実行したい!」という時があるかもしれません。(ちょっと特殊なケースですが…)
そんな時に使うのが `fallthrough` というキーワードです。
`case` の処理の最後に `fallthrough` と書いておくと、その `case` の処理が終わった後、次の `case` の条件を評価せずに、無条件で次の `case` の処理を実行します。
package main import "fmt" func main() { num := 2 switch num { case 1: fmt.Println("1の処理") fallthrough // これがあると下に落ちる! case 2: fmt.Println("2の処理") // numが2なので、まずここが実行される fallthrough // これがあると下に落ちる! case 3: fmt.Println("3の処理") // fallthroughがあるので、ここも実行される default: fmt.Println("defaultの処理") } } // 実行結果: // 2の処理 // 3の処理
上の例では、`num` が `2` なので、まず `case 2:` の処理が実行されます。そして `fallthrough` があるので、`case 3:` の条件は無視されて、`case 3:` の処理も続けて実行される、という流れです。
`fallthrough` は、処理が下に「落ちる (fall through)」ようなイメージですね。
ただ、この `fallthrough`、便利なようでいて、意図しない動きを生みやすい側面もあります。
`fallthrough`は、使う場面をよく考えて使わないと、予期せぬ動きをする原因になるので、本当に必要な場面以外では、あまり使わない方が無難かもしれません。使うときは、「なぜここで `fallthrough` が必要なのか」をコメントで残しておくと良いでしょう。
型switch文(タイプスイッチ):インタフェースの型で分岐
Go言語には `interface{}` という、どんな型でも入れることができる特別な型があります。まるで魔法の箱みたいですね!
でも、この魔法の箱に入っているものが、「本当は数値なのか?文字列なのか?それとも別の何か?」を知りたい時があります。
そんな時に活躍するのが「型 `switch` 文(タイプスイッチ)」です。
これは、`interface{}` 型の変数の中身が、実際にどの型なのかによって処理を分岐させるための `switch` 文です。
package main import "fmt" func printType(x interface{}) { // 引数xはどんな型でも受け取れる switch x.(type) { // 変数.(type) という特別な書き方 case int: fmt.Println("これは整数(int)です") case string: fmt.Println("これは文字列(string)です") case bool: fmt.Println("これは真偽値(bool)です") default: fmt.Printf("これは %T 型です\n", x) // %T で型名を表示できる } } func main() { printType(100) printType("こんにちは") printType(true) printType(3.14) // float64型 } // 実行結果: // これは整数(int)です // これは文字列(string)です // これは真偽値(bool)です // これは float64 型です
書き方は `switch 変数名.(type) { ... }` という、ちょっと特別な形になります。
`case` の後ろには、比較したい型名(`int`, `string`, `bool` など)を書きます。
さらに、型を判定するだけでなく、その型の値として変数に取り出すこともできます。
func printValue(x interface{}) { switch v := x.(type) { // vに型アサーションされた値が入る case int: fmt.Printf("整数の値: %d\n", v) // vはint型として使える case string: fmt.Printf("文字列の値: %s\n", v) // vはstring型として使える default: fmt.Printf("その他の型: %T, 値: %v\n", v, v) // vは元の型として使える } } // printValue(123) を実行すると "整数の値: 123" と表示される
`switch v := x.(type)` のように書くと、`case` 節の中で変数 `v` がその型に合った値として使えるようになります。これを「型アサーション」と組み合わせた書き方といいます。
関数の引数で色々な型の値を受け取る可能性がある時などに、この型switchはとても役立ちます。コードが安全かつ分かりやすくなりますね。
Go言語「switch文」を使う上での注意点
便利な `switch` 文ですが、使う上で少しだけ気をつけておきたい点もあります。
初心者のうちにつまずきやすいポイントをいくつか挙げておきますね。
暗黙の `break` を忘れない
Go言語では、一致した `case` の処理が終わると自動で `switch` を抜けます。他の言語の経験があると、`break` を書き忘れて次の `case` に処理が落ちることに慣れているかもしれませんが、Goでは逆です。`fallthrough` は計画的に
上で説明した `fallthrough` は、意図的に次の `case` も実行させたい場合にのみ使います。型は合わせよう
`switch` の後ろに書いた式の結果の型と、`case` の後ろに書く値の型は、基本的に同じである必要があります。(型 `switch` は例外です)。`default` の位置
`default` は `switch` 文の最後に書くのが一般的ですが、実は途中に書くこともできます。ただ、途中に書くとコードが読みにくくなることが多いので、特別な理由がない限りは最後に書くのがおすすめです。これらの点に気をつければ、`switch` 文をより安全に、そして効果的に使うことができるはずです!
【まとめ】Go言語の「switch文」でスマートな条件分岐を
今回は、Go言語の条件分岐の頼れる助っ人、`switch` 文について解説してきました!
いかがでしたか?
この記事で学んだ重要なポイントを振り返ってみましょう。
- `switch` 文は、複数の条件分岐をスッキリ書くための仕組み。
- 基本的な構文は `switch 式 { case 値: ... default: ... }`。
- Goの `switch` は、一致した `case` の処理が終わると自動で抜ける(暗黙の `break`)。
- カンマ区切りで複数の値を一つの `case` で扱える。
- `switch` の後ろに式を書かないで、`case` に条件式を書くこともできる(`if-else if` の代替)。
- `fallthrough` を使うと、あえて次の `case` の処理も実行できる(注意して使おう!)。
- `switch 変数.(type)` で、`interface{}` 型の中身の型によって処理を分岐できる(型 `switch`)。
`if` 文しか知らなかった時と比べて、条件分岐の書き方の選択肢がグッと増えたのではないでしょうか。
`switch` 文を使いこなせるようになると、たくさんの条件を扱うコードがビックリするほど読みやすくなりますし、Go言語らしいスマートなプログラムを書くための一歩にもなります。
【関連記事】 Go言語とは?特徴・できること・将来性
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。