こんにちは､ そしてようこそ｡ この講義では､ switch文についてお話したいと思います｡
if文の代わりとなるものですが､
通常は特定の状況でのみ使用します｡
しかし､ if文の中で繰り返しを行うための素敵な構文が用意されています｡
そのため､ 条件演算子やif than else文を使えば､ 2つの選択肢から選ぶプログラムを簡単に書くことができます｡
質問や判断がとてもしやすいですね｡
しかし､ 多くの場合､ プログラムはいくつかの選択肢の中から1つを選択する必要があります｡
そして､ これは本質的にif else
if else if else if else if ifであろう｡
選択肢がいくつかあるときにif文で実装するのは当然ですが､
else ifが100個くらいできそうで面倒です｡
だから､
面倒だし､ エラーも出やすいし､ 本当に面倒くさいだけなんです｡ まるで定型文のようなコードを書いているようです｡
だから､ この構文に代わるもので､ switchでできることはすべてifでできる｡
でも､ その方がきれいだし､ 簡単だし､ 実際にも効率的なんです｡
そこで､ ある変数の値を異なる値とうまく比較する場合には､ switch文を使用します｡
そして､ この意味は､ if文があって､ さらにelse if､ else if､ else if､ else if､ else
ifがある場合､ switch文を使ってください｡
さて､ そのブール式がもう少し複雑であれば｡
switch文は使えません｡ switch文が使えるのは､
定数のような値と比較するときだけです｡
そんな複雑な表現ができるわけがない｡
しかし､ switch文を使う方がはるかに便利で非常に効率的であり､ ほとんどの言語がこの構成も持っています｡
そして､ とても素敵なのをご覧ください｡ 多くの言語がcをベースに構築されていることに気づかされます｡
プログラミングをしたことがある人なら､
これらの構成要素は､ もともとcやbeといった以前の言語で出てきたものなので､
よく見て知っているはずです｡
では､ switch文の構文を説明します｡ スイッチのキーワードがあるんですね｡
そして､ スイッチの中には､ この左右の括弧があり､
これが式となります｡ つまり､ 冒頭のif文と同じように見えるのですが､
ifキーワードの代わりにswitchキーワードがあるのです｡
そして､ 左のブラケットを手に入れます｡
必要な左のブラケット｡ その左のブラケットからスイッチ本体が始まります｡
そして､ 一番下にある右のブラケットで､ スイッチ本体が終了するのがわかります｡
もう一つ､ ここで重要なのは､ このキーワードのケースです｡
caseは､ 実はif文そのもののようなものです｡
だからswitchは実際には､
必ずしも真か偽かではなく､ 式を見ていくことになる｡
スイッチは､ 変数を見ているだけかもしれないし､ 何かあるかもしれない｡
そして､ case文の中でその変数を評価することになるのです｡
つまり､ 値1が表現に等しい場合､
値nが表現に等しい場合｡
しかし､ これはスイッチがトップレベルにあり､
ケースはそれぞれif文で､ スイッチの式と値を比較するようなものだと見ることができます｡
だから､ ケースもキーワードになる｡ また､ ケースの後にコロンがあることにお気づきでしょうか？
ケースがあって､ 自分の価値があるわけです｡
そしてその中に､ 複数のプログラムステートメントを用意することができます｡
そして､ 最後にはブレイクキーワードがありますね｡ これもキーワードですね｡ つまり､ ここには3つのキーワードがあり､
実際には4つのキーワードがあるのです｡ switchキーワード､ caseキーワード､ breakキーワード､
そして一番下にdefaultがありますね｡
つまり､ これらが重要な気付きとなります｡ 詳しい例を見ていきますが､
いろいろなケースが考えられます｡ そしてまた､ これはif else､ if else､ if else､ if elseのようにやっているだけなのです｡
つまり､ 値1が等しい式であれば､ コードを実行します｡
もし､ 値2が式に等しければ､
それを評価する｡ もし､ 値3が式に等しければ､ それを評価する｡
もし､ 値nがexpressionに等しければ､ そのブロックの中のコードを実行する｡
そして､ ケースのブロックはコロンで始まり､ ブレークで終わります｡
そして､ そこにその区切りがないと､ 他のケースを突き破って落ちてきてしまう｡
またその話をします｡
そして､ ここで最後に重要なのが､ このデフォルトキーワードです｡ これは基本的に､ 下の方にあるelse､ else
if､ else if､ else if､ then elseのことです｡
つまり､ 他のどのケースも式に評価されない場合､ これが設定される｡
それでは､ 先ほど申し上げたような細かい部分についてお話します｡
括弧で囲まれた式は､ 値との比較に成功します｡
そこで､ もう一度､
構文に戻ると､ expressionはすべての値と比較されます｡
そして､ いずれかの値と等しければ､ その値の中にあるコードを実行するのです｡
ケースは､ 単純な定数または定数式（定数に評価される式）でなければなりません｡
つまり､ x＋yのスイッチを入れれば､ xが5なら10のスイッチが入り､
値を10と比較することができるのです｡
でも普通は､ 何らかの数値に等しい変数にスイッチを入れるんですよね｡
その値が式の値と等しいケースが見つかった場合､ そのケースに続くステートメントが実行される｡
複数の文が含まれる場合､ それらは中括弧で閉じる必要はありません｡
つまり､ 複数の文が含まれる場合､
格言の文には中括弧は必要ない､
ということですね｡
if文の場合､ 常にそのブレースが必要であることを思い出してください｡
1行ずつ並べるだけでいいんです､ 重要なのはそこの区切りです｡
break文は､ 特定のケースの終了を知らせ､
文の実行を終了させる､ それはジャンプアウトする｡
そこで区切りをつけないと､ 次のケースで落ちてしまう｡
だから､ すべてのケースにbreak文の末尾を入れたいのです｡ ブレークを入れないときは､ たいていバグがあるかどうかということです｡
ブレークを入れたいのは､ コードを実行したい条件が複数ある場合です｡
だから､
複数のケースがあった場合､ 基本的に表現がこのケース､
このケース､ このケースだったら､ 同じことをやってくださいということで､
区切りの部分を取り出すことになります｡
そのため､ 区切りがあると､ 次のケースで特定のブロックが実行されているかどうかが問題になることがあるので､
注意が必要です｡
デフォルトと呼ばれる特別なオプションケースは､ 式の値がどのケースにも一致しない場合に実行されます｡
それは､
どのケースも当てはまらない場合に起こる､ フォールスルーと同じです｡
ここでは､ 列挙型を評価するためのスイッチを作成する例を紹介します｡
この場合､ weekdayというenum型があり､ それをすべての平日で指定しているだけです｡
そして､ enum weekdayという型の変数を作り､ それを月曜日に設定し､ 今日に切り替えています｡
つまり､ 変数であるtodayの値に応じて､ case文のいずれかが実行されることになります｡
今日が日曜日と同じなら､ 今日は日曜日とプリントアウトして､
飛び出す｡
今日が月曜日と同じなら､ 今日が月曜日とプリントアウトして飛び出すんです｡
どれにも当てはまらない場合は､
デフォルトのケースに入ります｡ では､ この例をコードブロック単位で実行してみましょう｡
ここでは､ サンプルコードを紹介します｡ そして､ 今日は月曜日と等しいので､
ケースMondayが評価され､
今日は月曜日であると出力されることがわかります｡
では､ このコードをビルドして実行してみましょう｡ それを見るのが､ 今日は月曜日です｡
なぜなら､ ここで起きていることは､ 今日が月曜日になることだからです｡ このように､ 今日の変数を評価したい式を置いてから評価するのです｡
ここで覚えておきたいのは､ 16行目のswitch文を開始する括弧と､
29行目のswitch名を終了する括弧を持つことです｡
括弧を使わなくても､ それぞれのcase文の中に複数の行を入れることができます｡
では､ 月曜日以降にブレイクステートメントを取り出すとどうなるか見てみましょう｡
なぜなら､ ブレイクはケースからすぐに飛び出すことを忘れてはならないからです｡ しかし､ これを削除すると､
どうなるかというと､ 火曜日まで落ちてしまい､
今日の月曜日と今日の火曜日で両方のprintfsが実行されることになるのです｡
これで､ プログラムを実行すると､ 今日は月曜日､
今日は火曜日と表示されるようになりました｡
それがブレイクステートメントの重要性です｡
ブレイクが飛び出す｡
ですから､ 月曜日と火曜日で同じ出力をしたい場合に便利かもしれません｡
例えば､ このようにcase文を見ることがありますが､
case Tuesdayは同じ出力が欲しいからで､ 変数が何に等しいかは関係ないのです｡
というようなことがあるかもしれませんが､ 実行が異なる別々のcase文を持つ場合､
そこにブレークを追加する必要があるのです｡
だから､ 日曜､ 月曜､ 火曜しか見ていない｡
それに合致するケースがないため､ todayの値をSundayと同じにしたらどうなるでしょうか｡
まあ､ どうなるかというと､ デフォルトで落ちて､ 何でもかんでもプリントアウトされることになる｡
では､ もう一度実行してみましょう｡
そして､ 今日は日曜日であることがわかります｡
すみません､ 間違った変数に設定しました｡ 設定したいのは､ 仮に水曜日とします｡
日曜の案件がありました｡
では､ 実際にどのケースにもマッチしなかったので､ 何でもかんでもプリントアウトしてしまうことを確認します｡
だから､ スイッチに必要なのは､ 本当に構文を覚えることだけなんです｡
式は括弧の中に入る......それが評価するものです｡
ケースは式と一致する必要があります｡ そのため､ 定数や特定の定数値で評価される式でなければならないのですが､
通常は変数を使っています｡
そして､ それぞれのモノのケースと､ デフォルトのオールケースを用意し､ 休憩も忘れないようにするのです｡
もう少し話を戻して､ ケースを使ったswitchコンストラクトの別の例を見てみましょう｡
この次の例では､ ちょっと違いますね｡
ここでやっているのは､ ユーザーからデータをもらって､ それを元にスイッチングすることです｡
この例では､ メイン関数の中で､ まず2つの浮動小数点を作成し､
次に文字演算子を作成し､ ユーザーに値､ 演算子､ 値2を入力するよう求めています｡
そして､ フォーマット指定子を使って区別しているのですが､ どれもアンパサンドというアドレスを持っています｡
演算子に入力する文字がプラスマイナスなのかスターなのかによって､
それをスイッチケースに含めたい｡
つまり､ ユーザーがプラスを入力した場合､
次のコラムにあるように､ スイッチコンストラクトで､ オペレーターに切り替わるのです｡
演算子の値､ 変数演算子の値と､ このcase文の一つ一つを比較することになるのです｡
また､
これらのcase文は､ 文字を比較するため､ 一重引用符で囲まれていることにお気づきでしょう｡
そのため､ 数値や変数と値特定の定数､
文字と特定の定数を比較することができます｡
そして､ それぞれのcase文の中で､ 特定の書式をプリントアウトしているのです｡
価値1プラス価値2､ 価値1マイナス価値2｡
実際にプリントで計算を行なっています｡
そしてまた､ 重要なブレーク・ステートメントが目に飛び込んできますが､
これは他のケースに落ちないようにするために必要なものです｡
また､ 最後のcase文では､ フォワードスラッシュが仕切りになっていますが､ これはif文であることにお気づきでしょうか｡
括弧をつけずに各ケースで複数のステートメントを持つことができるため､
ケースを囲む括弧はつけていません｡
つまり､ 最後のケースは､ 値2が0に等しい場合､ 0によって割り切れないことを確認するために､
ちょっとしたチェックをしているのです｡
そして､ 0で割らなければ､ 実際に割り算を実行することになります｡
そして､ そのケースの一番最後に､ もう一回休憩があるんです｡
私たちのデフォルトのケースは､ 私たちが処理する方法を知らないオペレータを入力したと言うことです｡
しかし､ スイッチステートメントは非常に効率的です｡
特定の変数に多くの異なる値を比較し､ その後､ 異なることを行いたいときはいつでも､
非常に素早く書くことができます｡
最後に､ 意思決定に関連するgo to文について触れたいと思います｡
直接の決定文ではなく､
ラベルを使って別の行に飛ぶという感じなのですが､ cで使えるということで､
触れておきたいと思いました｡
go to文には､ ラベルとgo toキーワードの2つのパートがあるんだ｡
Fortranやその他の基本的な言語でプログラミングをしたことがある人は､
おそらくこれを知っているでしょうし､ かなり使ったことでしょう｡
さて､ cの話ですが､ 本当に使う必要はないです｡
ちょっとだけ説明しますが､
あるコードに飛び出して､ そのコードのどの行にも行くことができるのです｡
使い方が非常に難しいというのも､ 嫌われる理由のひとつです｡
プログラムのメンテナンスをしていて､ シーケンシャルなものであれば､ 一行一行､
whileループの中のif文を見ています｡
whileループの中にif文があるとまずいですね｡
しかし今､ 基本的にソースコードの27行目にいて､ go toキーワード以外の理由なく800行目にジャンプするようなことがあれば､
突然大量のコードをスキップすることになり､ 保守やフォローが非常に難しくなります｡
だから､ 行くべき2つのパートとレーベル名｡ ラベルの名前は､ 変数の名前と同じように､
英数字､ 数字で始めることはできませんが､ アンダースコアで始めることができます｡
は､ アンダースコアで始めることができます｡
基本的にはgo toキーワードを使うだけで､ 何かの識別子､ パート2に行くわけです｡
後編はどこかのレーベルです｡
ですから､ 実際にそのコード行にジャンプするためには､ そのコード行にラベルを貼る必要があるのです｡
パート2という文言があるはずです｡
では､ その例を紹介しますが､ メンテナンスに問題があるため､
本当に絶対に使わないでください｡
しかし､ 以前にプログラミングをしたことがあり､ 使い慣れた方なら触れておきたいと思ったのです｡
cでは､ それほど使う必要はないでしょう｡
私が見た中で､ 役に立ちそうな使用例が1つあります｡
先日､ 同僚のプログラマと一緒に仕事をしていたのですが､
そのプログラマは入れ子のループや入れ子のif文がたくさんありました｡
でも､ 本当はループの方が良い例かもしれませんね｡ ループを､ 覚えて､ コードを繰り返す｡ ネストしたループをたくさん持っていた｡
そして､ 5つ目のような一番内側の入れ子ループでは､ 何らかの条件があるため､
すべてのループから飛び出そうとしました｡
それで､ そのループから飛び降りるために､ よく通っていたんです｡
ループから抜け出すもう1つの方法は､ brakeキーワードを使うことですが､
brakeは最も内側のループからしか飛び出せません｡
そのため､ フラグを大量に設定し､ ループをすべて終了させるif文を大量に用意しなければ､
効果的な方法がありませんでしたので､ 以前はif文にアクセスしていました｡
そしてそれは､
書かなければならないコードの量が減り､ 何が起こっているのかがはっきりするので､ かなり有用だと思った一件でした｡
ある条件を満たしたから､ すべての入れ子ループから飛び出しただけなんですね｡
そして､ それは1つのケースです｡ しかし､ ほとんどの場合､ 本当に行く必要はありませんし､
先ほど述べたような理由で､ 非常に問題があります｡
しかし､ go toは他の言語で使うのと同じように使うだけです｡
レーベル名でGO TOキーワードがあるんですね｡
そして､ コードでは､ ラベルのあるコード行にジャンプすることになるのです｡
だから､ いろいろなコードを省略できる｡
つまり､ この例では､ topというラベルがあり､ コロンがありますね｡
それでレーベルだとわかるんですね｡
そしてtopにはいくつかの発言があります｡ そしてその一番下に､ if文がありますよね｡
そして､ charがyに等しい場合､ トップに行くということですね｡
このように､ コードの中であちこちに飛び火してしまい､ フォローが非常に難しくなることがお分かりいただけたと思います｡
だから､ 何個も何個もネストしたループがあって､ すべてのループから飛び出したい場合以外は､
基本的に使わないでください｡ ありがとうございます｡