Chapter 08

if 式

if 式

if 式を使うと,「ある条件を満たすときだけ処理をする」ということができます.これを条件分岐といいます.

if 式を使ったプログラムの例は次のようになります.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x < 10 {
        println!("10 未満");
    }
    println!("終了");
}

コード中に if と書かれ,その後に x < 10 という条件が書かれています.それに続く {} で囲まれた部分は, x < 10 が成り立つときにだけ実行されます.

x < 10 が成り立たないとき, {} で囲まれた部分は無視されて,その続きから実行されます.

つまり,このコードを実行すると

入力された値 println!("10 未満"); println!("終了"); 標準出力
10 未満の場合: 実行される 実行される 10 未満
終了
10 以上の場合: 実行されない 実行される 終了

となります.

if はキーワードです(if という名前の変数は使えません).

条件式

今回, x < 10 と書くことで「x が 10 より小さい」という条件を表すことができました.このように 2 つの値を比較するための書き方にはこれらがあります:

書き方 対応する数式 意味
x == y x = y x と y は等しい
x != y x \neq y x と y は等しくない
x > y x > y x は y より大きい
x < y x < y x は y より小さい
x >= y x \geq y x は y 以上
x <= y x \leq y x は y 以下

たとえば,整数を受け取って,その値が 10 だったときに入力された値は 10 です.と出力するプログラムは次のように書きます.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x == 10 {
        println!("入力された値は 10 です.");
    }
}

ここで x = 10 (イコール 1 つ)ではなく x == 10 (イコール 2 つ)であることに注意してください.間違えてイコールを 1 つにしてしまうと,

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x = 10 {
        println!("入力された値は 10 です.");
    }
}

エラーになります.

error[E0308]: mismatched types
 --> src/main.rs:7:8
  |
7 |     if x = 10 {
  |        ^^^^^^
  |        |
  |        expected `bool`, found `()`
  |        help: try comparing for equality: `x == 10`

expected `bool`, found `()`の意味については今は説明しませんが,その後の help: try comparing for equality: `x == 10` というのは「2 つの値を比較して等しいか調べるには x == 10 と書いてください」という意味です.

条件の組み合わせ

かつ

2 つの整数 xy を受け取って,どちらも正であったときにのみどちらも正ですと出力するプログラムを考えます.ここまでの内容を使うと,次のように書けます.

use proconio::input;

fn main() {
    input! {
        x: i32,
        y: i32,
    }
    if x > 0 {
        if y > 0 {
            println!("どちらも正です");
        }
    }
}

if 式が 2 つあって, 1 つめの if 式の条件は x > 0 , 2 つめの if 式の条件は y > 0 です.このプログラムの動作は次のようになります.

  • もし x \leq 0 ならば, 1 つめの if 式で中身が実行されずそのまま終了します.
  • もし x > 0 だけれども y \leq 0 ならば, 1 つめの if 式の中身は実行されますが,その中の 2 つめの if 式で中身が実行されないので,結局何も出力されず終了します.
  • もし x > 0 かつ y > 0 ならば, 1 つめの if 式の中身が実行され,その中の 2 つめの if 式の中身も実行されることになるので,どちらも正です と出力されます.

こうして, x > 0 かつ y > 0 の場合のみどちらも正ですと出力されます.

実は,&& 演算子というものを用いると,このような「p かつ q」という条件を次のように簡単に書くことができます.

use proconio::input;

fn main() {
    input! {
        x: i32,
        y: i32,
    }
    if x > 0 && y > 0 {
        println!("どちらも正です");
    }
}

x > 0y > 0どちらも成り立つときに if 式の中身が実行されます.これを表にすると次のようになります.

p && q q: 成り立つ q: 成り立たない
p: 成り立つ 実行される 実行されない
p: 成り立たない 実行されない 実行されない

また, x = y = 0 という条件を, x == y == 0 と書くことはできません.

use proconio::input;

fn main() {
    input! {
        x: i32,
        y: i32,
    }
    if x == y == 0 {
        println!("どちらも 0 です");
    }
}

次のようなエラーになります.

error: comparison operators cannot be chained
 --> src/main.rs:8:10
  |
8 |     if x == y == 0 {
  |          ^^   ^^
  |
help: split the comparison into two
  |
8 |     if x == y && y == 0 {
  |               ^^^^

comparison operators cannot be chained は「比較演算子はつなげて書くことができない」という意味です. split the comparison into two は「比較を 2 つに分けて書いてはどうか」という提案です.言われた通り,「x = y = 0」を「x = y かつ y = 0」あるいは「x = 0 かつ y = 0」などと言い換えて x == 0 && y == 0 のように書くと,正しく動きます.

use proconio::input;

fn main() {
    input! {
        x: i32,
        y: i32,
    }
    if x == 0 && y == 0 {
        println!("どちらも 0 です");
    }
}

同様に, 0 < x < 10 という条件も 0 < x < 10 とは書けず,「0 < x かつ x < 10」と言い換えて 0 < x && x < 10 と書きます.

または

2 つの整数 x と y を受け取って,少なくともどちらか一方が正であったときにのみ少なくともどちらか一方が正ですと出力することを考えます.「p かつ q」のときは && 演算子を使いましたが,今回の条件は「p または q」であり, || 演算子を使います.

use proconio::input;

fn main() {
    input! {
        x: i32,
        y: i32,
    }
    if x > 0 || y > 0 {
        println!("少なくともどちらか一方が正です");
    }
}

これを表にすると次のようになります.

p || q q: 成り立つ q: 成り立たない
p: 成り立つ 実行される 実行される
p: 成り立たない 実行される 実行されない

否定

! 演算子を使うと,条件の否定を行うことができます.

x > 0 という条件を否定するには,括弧でくくった上で前に ! を付けて !(x > 0) とします.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if !(x > 0) {
        println!("x は正ではありません");
    }
}

x > 0成り立たない場合のみx は正ではありませんと出力されます.

x > 0 の否定は x \leq 0 なので,これは x <= 0 と書いているのと同じです.

表にすると次のようになります.

!p p: 成り立つ p: 成り立たない
実行されない 実行される

かつ,または,否定は様々に組み合わせて使うことができます.

use proconio::input;

fn main() {
    input! {
        ave_precip: f64, // 年平均降水量 [mm]
        lowest_precip: f64, // 最小雨月降水量 [mm]
        threshold: f64, // 乾燥限界 [mm]
        lowest_temp: f64, // 月平均気温の最低 [℃]
    }
    if !(ave_precip < threshold)
        && lowest_temp >= 18.
        && (lowest_precip >= 60. || lowest_precip >= 100. - 0.04 * ave_precip)
    {
        println!("熱帯雨林気候(熱帯モンスーン気候含む)です");
    }
}

elseelse if

else

入力として整数 x を受け取り, x < 10 のときにx は 10 未満と出力し, x \geq 10のときにx は 10 以上と出力し,最後に終了と出力するプログラムを考えます.ここまでの内容を使うと,次のように書けます.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x < 10 {
        println!("x は 10 未満");
    }
    if x >= 10 {
        println!("x は 10 以上");
    }
    println!("終了");
}

しかし,x < 10x \geq 10 は常にいずれか一方のみが成り立つということが分かっています.このとき, else というものを使うと同じことが次のように書けます:

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x < 10 {
        println!("10 未満");
    } else {
        println!("10 以上");
    }
    println!("終了");
}

if 式の括弧 { } の直後に, else と括弧 { } で囲まれた部分が続いています.こうすると, if 式の条件が正しかったときは 1 つ目の括弧の中身が実行され,正しくなかったときは 2 つ目の括弧の中身が実行されます.表にすると次のようになります.

入力された値 10 未満 の出力 10 以上 の出力 終了 の出力 出力される内容
10 未満の場合: 実行される 実行されない 実行される 10 未満
終了
10 以上の場合: 実行されない 実行される 実行される 10 以上
終了

if と同様, else もキーワードです.

else if

else の直後にさらに if 式を書くこともできます.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x < 10 {
        println!("10 未満");
    } else if x < 20 {
        println!("10 以上 20 未満");
    }
}

これは,次のように書いているのと同じです.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x < 10 {
        println!("10 未満");
    } else {
        if x < 20 {
            println!("10 以上 20 未満");
        }
    }
}

x < 10 のときは 10 未満 と出力されます. x \geq 10 のときは else の中身が実行され,そのうち x < 20 のときだけ 10 以上 20 未満 と出力されます.

入力された値 10 未満 の出力 10 以上 20 未満 の出力 出力される内容
10 未満の場合: 実行される 実行されない 10 未満
10 以上 20 未満の場合: 実行されない 実行される 10 以上 20 未満
20 以上の場合: 実行されない 実行されない なし

else の後の if 式にさらに else を付ける場合は次のようになります.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    if x < 10 {
        println!("10 未満");
    } else if x < 20 {
        println!("10 以上 20 未満");
    } else {
        println!("20 以上");
    }
}
入力された値 10 未満 10 以上 20 未満 20 以上 出力される内容
10 未満の場合: 実行される 実行されない 実行されない 10 未満
10 以上 20 未満の場合: 実行されない 実行される 実行されない 10 以上 20 未満
20 以上の場合: 実行されない 実行されない 実行される 20 以上

実行の保証

変数について説明したときに,「変数に値は一度しか代入できない」と言いました.一方で, else の前の括弧 { } の中身と, else の後の括弧 { } の中身は,常にどちらか一方だけが実行されることが保証できます.よって,次のような書き方ができます.

use proconio::input;

fn main() {
    input! {
        x: i32,
    }
    let abs;
    if x >= 0 {
        abs = x;
    } else {
        abs = -x;
    }
    println!("絶対値は{}です", abs);
}

「どちらか一方しか実行されない」ため,二度以上の代入は起こりません.

また,「必ずどちらか一方は実行される」ため, abs は未初期化にならないことも分かります.よって,その後 println! の中で使うことができています.

else を使わずに if x >= 0if x < 0 を使って場合分けすると,このような保証を利用することができません.

いまは「どちらか一方だけが実行されることが保証できる」場合の例としてこのようなコードを挙げました.しかし,今回の場合に関しては,実際はこのような書き方をせず,代わりに let abs = if x >= 0 { x } else { -x }; と書くのが普通です(次章で説明します).

練習問題