Rustを極めたい - 3

前回の記事  
https://qiita.com/on_c98/items/f6541d6d793ad2a0b75d

# Rustの制御フロー

## 条件分岐

### if

Rustでは`if`を用いて条件分岐を行うことが出来ます。

```rust
fn main() {
	let num = 5;

	if num > 3 {
		println!("bigger than 3");
	} else {
		println!("smaller than 3");
	}
}
```

条件式に`()`は不要です。条件式には結果が`bool`値のみ指定可能で、C/C++等と違い、Rustでは`0`や`1`などを条件式に用いることはできません。
下記のような記述をした場合はコンパイルエラーとなります。

```rust
fn main() {
	let integer = 1;
	if integer {
		println!("true?")
	} else {
		println!("false?");
	}
}
```

```console
$ cargo run
   Compiling sample v0.1.0 (C:\path\to\sample)
error[E0308]: mismatched types
  --> src\main.rs:2:8
   |
2  |     if integer {
   |        ^^^^^^^ expected `bool`, found integer

For more information about this error, try `rustc --explain E0308`.
error: could not compile `sample` due to previous error
```

`else if`を用いることで、複数の分岐を扱うことが出来ます。

```rust
fn main() {
	let count = 1;

	if count == 1 {
		println!("one");
	} else if count == 2 {
		println!("two");
	} else {
		println!("{}", count);
	}
}
```

`if`は`式`なので、`let`で使用することが出来ます。

```rust
fn main() {
	let exp = true;

	let result = if exp { 1 } else { 0 };
}
```

上記の例では、`result`には値`1`が代入されます。`exp`が`false`の場合は、`0`が代入されます。

`if`を`let`で用いる場合、すべての分岐で同じ型を戻り値として返す必要があります。

```rust
fn main() {
	let exp = false;

	let result = if exp { 1 } else { "false" };
}
```

上記では、`true`の場合は`i32`を、`false`の場合は`&str`を返しているため、コンパイルエラーになります。

それぞれのブロック（`{}`）には`文`を記述することも可能です。

```rust
fn main() {
	let num = 10;

	let result = if num % 15 == 0 {
		println!("3と5の倍数です。");
		num / 15
	} else if num % 5 == 0 {
		println!("5の倍数です。");
		num / 5
	} else if num % 3 == 0 {
		println!("3の倍数です。");
		num / 3
	} else {
		println!("{}", num);
		num
	};

	println!("{}", result);
}
```

## 繰り返し

### loop

Rustでは、`loop`を用いて繰り返し処理をすることが出来ます。

```rust
fn main() {
	loop {
		println!("loop!");
	}
}
```

`loop`では条件式などは受け取らず、無限ループになります。`loop`から抜け出すには、`break`キーワードを用います。

```rust
fn main() {
	let mut count = 0;

	loop {
		println!("count: {}", count);
		if count > 10 {
			break;
		}
		count += 1;
	}
}
```

上記例では、`count`に1を足していき、10より大きくなったら`break`で`loop`処理を抜けます。

`break`には戻り値を渡すことが出来ます。

```rust
fn main() {
	let mut x = 0;
	let z = 5;

	let y = loop {
		x += 1;

		if x == z {
			break x * z;
		}
	}

	println!("y is {}", y);
}
```

上記例では、繰り返しのたびに`x`の値がインクリメントされていき、`z`の値と同等になった時点で、`x * z`の値がyに代入され`loop`処理を抜けます。

ネストされた`loop`で外側の`loop`から抜けたい場合、ラベルを用います。

```rust
fn main() {
    let mut x = 0;

    'outer_loop: loop {
        let mut y = 0;

        loop {
            if y == 10 {
                break;
            }

            if x == 2 {
                break 'outer_loop; //ラベルが付与されている外側のloopから抜ける
            }

            y += 2;
            println!("x: {}, y: {}", x, y);
        }
        x += 1;
    }
}
```

上記を実行した場合、下記のように出力されます。
```console
❯ cargo run
   Compiling sample v0.1.0 (C:\path\to\sample)
     Running `target\debug\sample.exe`
x: 0, y: 2
x: 0, y: 4
x: 0, y: 6
x: 0, y: 8
x: 0, y: 10
x: 1, y: 2
x: 1, y: 4
x: 1, y: 6
x: 1, y: 8
x: 1, y: 10
```

ネストされた内側の`loop`内で`break`を2か所使用していますが、`y == 10`の時に実行される`break;`ではラベルが指定されていないため、内側の`loop`からのみ抜けて、外側のloopは続行されます。`x == 3`の時に実行される`break 'outer_loop;`では、ラベル`'outer_loop`が指定されているため外側のループから抜けて処理が終了します。

### while

Rustでは、`while`を用いて条件付きの繰り返し処理を行うことが出来ます。上記の`loop`で作成したプログラムを`while`で記述する場合、下記のようになります。

```rust
fn main() {
    let mut x = 0;

    while x < 2 {
        let mut y = 0;

        while y < 10 {
            y += 2;
            println!("x: {}, y: {}", x, y);
        }
        x += 1;
    }
}
```

`loop`時に使用していた`if`や`break`、ラベル等が不要になり、よりすっきりした繰り返し処理を書くことが出来ます。

また、下記のようにすることでコレクションの中身を取り出し処理することが出来ます。

```rust
fn main() {
	let arr = [1, 2, 3, 4, 5];
	let mut index = 0;

	while index < 5 {
		println!("{}", arr[index]);
		index += 1;
	}
}
```

ただし、`while`でインデックスを使用したコレクションへのアクセスは、コレクションのサイズが変更された場合などに範囲外のインデックスへのアクセスが発生してしまい、プログラムがパニックを起こしてしまうため、あまり推奨されていません。

代わりに`for`を使用して安全にコレクションを処理することが出来ます。

### for

Rustの`for`では、配列などのコレクションから一つずつ要素を取り出しながら繰り返し処理をします。

```rust
fn main() {
	let a = [1, 2, 3, 4, 5];

	for value in a {
		println!("{}", value);
	}
}
```

上記の例では、配列`a`から一つずつ要素を取り出し、変数`value`として処理しています。要素数を気にすることなく、安全にコレクションを処理することが出来ます。

また、下記のように書くことで決まった回数をループさせることも可能です。

```rust
fn main() {
	for i in 0..10 {
		println!("{}", i);
	}
}
```

`0..10`は、0から9までの`Range`を表しており、10回ループさせることが出来ます。
`0..=10`と書くことで、0から10までの`Range`を表現することも可能です。

## 終わりに

次回は`struct`（構造体）について書いていこうと思います。


## 参考
https://doc.rust-lang.org/book/ch03-05-control-flow.html