目次
1. エラーになったコード
fn max_value(nums: &[i32]) -> Option<&i32> {
if nums.is_empty() {
None
}
let mut current_max = &nums[0];
for num in nums.iter() {
if num > current_max {
current_max = num;
}
}
Some(current_max);
}
fn main() {
let nums = vec![10, 5, 42, 7];
println!("{:?}", max_value(&nums));
let empty = vec![];
println!("{:?}", max_value(&empty));
}
このコードでは、max_value
関数を定義して、配列に含まれる最大値を返すことを意図している。配列が空である場合は None
を返す。Rust では、戻り値の型を統一する必要がある。返す値があるか(=最大値が含まれる)ないか(=None
である)場合は、Rust では Option
型を使い表記する。
返す値は正しく Option
型に含まれているものであるのに、このコードはエラーが発生してしまう。
2. エラーの原因と対策
上記のコードでは2つのエラーがある。
2.1. 早期リターンのNone
if nums.is_empty() {
None
}
この書きかただとNone
という値を評価しただけで処理が続いてしまい、関数を抜けない。Rust の戻り値は return
を使わない方法もあるが、これは関数の最後の式でないといけない。早期リターンの場合は、return None;
のように return
を使って書く必要がある。
2.2. Someにセミコロンをつけた
Rust では関数の最後の式が戻り値になるルールがある。
-
Some(current_max)
(式) $\rightarrow$ そのまま戻り値 -
Some(current_max);
(文)$\rightarrow$ 値が捨てられて()
(=Unit 型)が返る
つまり、セミコロンを付けると「戻り値なし」と解釈されてしまい、型が合わなくなるので、Some(current_max)
をセミコロンを外す必要がある。
あるいは、(1) と同様に return
を使って書くこともできる。
3. 修正版コード
修正されたコードは次の通りになる。
fn max_value(nums: &[i32]) -> Option<&i32> {
if nums.is_empty() {
return None;
}
let mut current_max = &nums[0];
for num in nums.iter() {
if num > current_max {
current_max = num;
}
}
Some(current_max) // ← セミコロンなし
}
fn main() {
let nums = vec![10, 5, 42, 7];
println!("{:?}", max_value(&nums)); // Some(42)
let empty: Vec<i32> = vec![];
println!("{:?}", max_value(&empty)); // None
}
4. まとめ
- Rust では最後の式が戻り値になる
- 途中で関数を終わらせたいときは
return
を明示する - セミコロンをつけると「文」になり、Unit 型が返る