クエスチョンマーク演算子 '?'
CoddyのRustジャーニー「Logic & Flow」セクションの一部 — レッスン 46/66。
Resultを返す関数を扱う際、ローカルでエラーを処理するか、呼び出し元の関数にエラーを渡すことで、エラーを処理する必要が頻繁にあります。Rustは、この一般的なパターンに対してエレガントな演算子を提供しています。それがクエスチョンマーク演算子 ? です。
? 演算子は、冗長な match 文を書くことなく、エラーを伝播させるためのクリーンな方法を提供します。Result の後に ? を置くと、自動的に Ok の値をアンラップするか、または Err を伴って現在の関数から即座にリターンします。
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> {
let number = s.parse::<i32>()?; // パースに失敗した場合は、エラーを返す
Ok(number * 2) // 成功した場合は、数値を2倍にする
}これは、完全な match 文を書くのと同等ですが、ずっと簡潔です。もし s.parse::<i32>() が Ok を返す場合、? はその値を抽出し、number に代入します。もし Err を返す場合は、? は即座にそのエラーを関数全体から返します。
? 演算子は、エラーを返す必要があるため、Result(または Option)を返す関数内でのみ使用できます。
チャレンジ
簡単2つの入力を受け取ります。最初の入力は整数にパースされるべき文字列で、2番目の入力も同様に整数にパースされるべき文字列です。2つの文字列スライスをパラメータとして受け取り、Result<i32, std::num::ParseIntError>を返すadd_numbersという関数を作成してください。関数内では、?演算子を使用して両方の文字列をパースし、それらの合計をOkで包んで返します。2つの入力を使用してこの関数を呼び出し、matchを使用して結果を処理してください。
要件:
- 最初の入力(文字列としての最初の数値)を読み込み、空白をトリミングする
- 2番目の入力(文字列としての2番目の数値)を読み込み、空白をトリミングする
- 2つの
&strパラメータを受け取り、Result<i32, std::num::ParseIntError>を返す関数add_numbersを作成する - 関数内で、
?演算子を使用して最初の文字列をi32にパースする ?演算子を使用して2番目の文字列をi32にパースする- パースされた両方の数値の合計である
Ok(sum)を返す - 2つの入力文字列を使用して関数を呼び出す
match式を使用してResultを処理するOk(value)アームでは、Sum: [value]と出力するErr(_)アームでは、Parsing errorと出力する
入力:
- 1行目: 数値を表す文字列 (例:
15) - 2行目: 別の数値を表す文字列 (例:
27)
出力:
- 両方の文字列が有効な数値の場合:
Sum: [result] - いずれかの文字列がパースできない場合:
Parsing error
チートシート
クエスチョンマーク演算子 ? は、Result を返す関数においてエラーを伝播させるための簡潔な方法を提供します。
Result の後に置かれた場合、? 演算子は以下の動作をします:
Ok値をアンラップして実行を継続する- エラーが発生した場合は、現在の関数から即座に
Errを返す
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> {
let number = s.parse::<i32>()?; // パースに失敗した場合は、エラーを返す
Ok(number * 2) // 成功した場合は、数値を2倍にする
}? 演算子は、Result または Option 型を返す関数内でのみ使用できます。
自分で試してみよう
use std::io;
// TODO: ここにadd_numbers関数を作成してください
// 2つの&strパラメータを受け取り、Result<i32, std::num::ParseIntError>を返す必要があります
fn main() {
// 最初の入力を読み込む
let mut input1 = String::new();
io::stdin().read_line(&mut input1).expect("Failed to read line");
let input1 = input1.trim();
// 2番目の入力を読み込む
let mut input2 = String::new();
io::stdin().read_line(&mut input2).expect("Failed to read line");
let input2 = input2.trim();
// TODO: input1とinput2を使用してadd_numbersを呼び出す
// TODO: matchを使用してResultを処理する
// Ok(value)の場合は "Sum: [value]" を出力する
// Err(_)の場合は "Parsing error" を出力する
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
Logic & Flowのすべてのレッスン
7'Result' によるエラーハンドリング
'Result' とは?'Result' で 'match' を使うis_ok() と is_err()ショートカット: unwrap と expectクエスチョンマーク演算子 '?'文字列から数値へのパースまとめ - 安全な除算関数