if

プログラムの実際の作業は式によって実行されることを学んだ。これまで見てきたすべてのプログラムの式は、main()関数で始まり、mainの終わりまで実行されていた。

一方、文は、式の実行に影響を与える機能だ。文は値を生成せず、それ自体には副作用もない。文は、式が実行されるかどうか、および実行される順序を決定する。文は、そのような決定を行う際に、論理式を使用する場合がある。

注釈:他のプログラミング言語では、式と文の定義が異なる場合や、その区別がまったくない場合もある。

ifブロックとそのスコープ

if文は、1つ以上の式が実行されるかどうかを決定する。これは、論理式を評価して決定する。これは、"コーヒーがあれば、私はコーヒーを飲む"という文の"if"と同じ意味だ。

ifは、括弧で囲まれた論理式を受け取る。その論理式の値がtrueの場合、次の波括弧で囲まれた式が実行される。逆に、論理式がfalseの場合、波括弧で囲まれた式は実行されない。

波括弧で囲まれた領域はスコープと呼ばれ、そのスコープ内のすべてのコードはコードブロックと呼ばれる。

if文の構文は次の通りだ。

if (a_logical_expression) {
    // ... trueの場合に実行する式
}
D

例えば、"コーヒーがあるならコーヒーを飲んで、カップを洗う"を表すプログラム構造は、次のプログラムのように記述できる。

import std.stdio;

void main() {
    bool existsCoffee = true;

    if (existsCoffee) {
        writeln("Drink coffee");
        writeln("Wash the cup");
    }
}

existsCoffeeの値がfalseの場合、ブロック内の式はスキップされ、プログラムは何も出力しない。

elseブロックとそのスコープ

if文の論理式がfalseの場合に実行する操作がある場合がある。例えば、"コーヒーがあるならコーヒーを飲む、そうでない場合は紅茶を飲む"という決定では、常に実行する操作がある。

falseの場合に実行する操作は、elseキーワードの後のスコープに配置される。

if (a_logical_expression) {
    // ... trueの場合に実行する式

} else {
    // ... falseの場合に実行する式
}
D

例えば、常に紅茶があるとして、次のように記述する。

if (existsCoffee) {
    writeln("Drink coffee");

} else {
    writeln("Drink tea");
}
D

この例では、existsCoffeeの値に応じて、1番目の文字列か2番目の文字列のいずれかが表示される。

else自体は文ではなく、if文のオプションの節であり、単独では使用できない。

上記のifおよびelseブロックの波括弧の配置に注意。波括弧を別行に配置するのがD言語の公式スタイルだが、この本では、波括弧をインラインで配置する一般的なスタイルを統一して使っている。

スコープの波括弧は常に使用しよう

スコープ内に文が1つしかない場合は、中括弧を省略することも可能だが、お勧めはしない。ifelseのスコープには、それぞれ1つの文しか含まれていないため、このコードは次のように記述することもできる。

if (existsCoffee)
    writeln("Drink coffee");

else
    writeln("Drink tea");
D

経験豊富なプログラマーは、単一の文でも中括弧を使用する。(この章の演習問題の一つは、中括弧を省略することに関するものだ。)そうは言っても、中括弧を省略した方が実際に良い唯一のケースを紹介しよう。

"if、else if、else"の連鎖

文や式の力の一つは、より複雑な方法でそれらを使用できることだ。式に加えて、スコープには他の文を含めることもできる。例えば、elseスコープにはif文を含めることができる。文と式をさまざまな方法で接続することで、プログラムの目的に応じてインテリジェントに動作させることができる。

以下は、悪いコーヒーショップまで歩くよりも、良いコーヒーショップまで自転車で行くほうが望ましいという合意に基づいて、より複雑な例を書いたものだ。

if (existsCoffee) {
    writeln("Drink coffee at home");

} else {

    if (existsBicycle) {
        writeln("Ride to the good place");

    } else {
        writeln("Walk to the bad place");
    }
}
D

上記のコードは、"コーヒーがある場合は自宅で飲む。そうでない場合、自転車がある場合は良い場所まで自転車で移動する。そうでない場合は悪い場所まで歩く"という文を表している。

この決定プロセスをさらに複雑にしよう:悪い場所まで歩く代わりに、まず隣を試しよう:

if (existsCoffee) {
    writeln("Drink coffee at home");

} else {

    if (existsBicycle) {
        writeln("Ride to the good place");

    } else {

        if (neighborIsHome) {
            writeln("Have coffee at neighbor's");

        } else {
            writeln("Walk to the bad place");
        }
    }
}
D

"この場合、そうでない場合は、さらに別の場合は、さらに別の場合は、..."という決定は、プログラムではよく見られる。残念ながら、中括弧を常に使用するというガイドラインを頑固に守ると、コードは横方向と縦方向に余白が多すぎるものになってしまう。空行を無視すると、上記の3つのif文と4つのwriteln式は、合計13行を占めている。

このような構文をよりコンパクトに記述するために、elseスコープにif文が1つしか含まれていない場合、このガイドラインの例外として、そのelseスコープの波括弧は省略する。

より良い形式を示す前の暫定的なステップとして、以下のコードは整理されていないままにしておく。このような整理されていない形でコードを書くべきではない。

単一のif文のみを含む2つのelseスコープの波括弧を削除したコードは、次のようになる。

if (existsCoffee) {
    writeln("Drink coffee at home");

} else

    if (existsBicycle) {
        writeln("Ride to the good place");

    } else

        if (neighborIsHome) {
            writeln("Have coffee at neighbor's");

        } else {
            writeln("Walk to the bad place");
        }
D

ここで、これらのif文を、それらを囲むelse句と同じ行に移動し、コードを整理すると、より読みやすい次の形式になる。

if (existsCoffee) {
    writeln("Drink coffee at home");

} else if (existsBicycle) {
    writeln("Ride to the good place");

} else if (neighborIsHome) {
    writeln("Have coffee at neighbor's");

} else {
    writeln("Walk to the bad place");
}
D

中括弧を削除することで、コードがよりコンパクトになり、すべての式が整列して読みやすくなった。論理式、評価される順序、および真の場合に実行される操作が、一目でわかるようになった。

この一般的なプログラミング構文は"if、else if、else"の連鎖と呼ばれている。

演習
  1. 以下の論理式はtrueであるため、このプログラムはレモネードを飲み、カップを洗うことが予想される。
    import std.stdio;
    
    void main() {
        bool existsLemonade = true;
    
        if (existsLemonade) {
            writeln("Drinking lemonade");
            writeln("Washing the cup");
    
        } else
            writeln("Eating pie");
            writeln("Washing the plate");
    }
    しかし、このプログラムを実行すると、皿も洗われてしまう:
    レモネードを飲む
    カップを洗う
    皿を洗う
    なぜだろう?論理式がfalseの場合にのみ皿を洗うようにプログラムを修正。
  2. ユーザーとゲームをするプログラムを書いてみよう(もちろん、信頼関係があるもの)。ユーザーはサイコロを投げ、その値を入力する。サイコロの値に応じて、ユーザーかプログラムが勝者となる。
    サイコロの値プログラムの出力
    1あなたの勝ち
    2あなたの勝ち
    3あなたの勝ち
    4私の勝ち
    5私の勝ち
    6私の勝ち
    それ以外の値エラー: 無効な値
    ボーナス:値が無効な場合、その値もプログラムで表示するようにしよう。例えば、次のように。
    エラー: 7 は無効
  3. ユーザーに1から1000までの値を入力させるゲームに変更しよう。値が1から500の範囲であればユーザーが勝ち、501から1000の範囲であればコンピュータが勝つ。前のプログラムを、このように簡単に変更できるかな?