クエスチョンマーク演算子 '?'
CoddyのRustジャーニー「論理とフロー」セクションの一部。レッスン 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 を返す場合、? はそのエラーを関数全体から直ちに返します。
::<i32>構文に注目してください。これはturbofishと呼ばれ、文字列をどの型に解析するかをRustに伝えます。この関数はResult<i32, std::num::ParseIntError>を返します。ここで、i32は成功時の型であり、std::num::ParseIntErrorは解析に失敗したときに返されるエラー型です。
?演算子は、エラーを返せる必要があるため、Result(またはOption)を返す関数でのみ使用できます。
チャレンジ
簡単2つの入力を受け取ります。first input は整数として parsing されるべき文字列で、second input は同様に整数として parsing されるべき別の文字列です。add_numbersという名前のfunctionをCreateし、2つの文字列スライスをparametersとして受け取り、Result<i32, std::num::ParseIntError>をreturnするようにします。function内では、?演算子を使用して両方の文字列をparseし、それらの合計をOkで包んでreturnします。2つの入力を使ってfunctionをCallし、matchを使用してresultをhandleします。
要件:
- first input(文字列としてのfirst number)をreadし、空白をtrimする
- second input(文字列としてのsecond number)をreadし、空白をtrimする
- 2つの
&strparametersを受け取り、Result<i32, std::num::ParseIntError>をreturnするadd_numbersというfunctionをCreateする - function内で、
?演算子を使用してfirst stringをi32にparseする ?演算子を使用してsecond stringをi32にparseする- parseされた両方のnumberの加算であるsumを
Ok(sum)としてreturnする - 2つのinput stringsを使ってfunctionをCallする
matchexpressionを使用してResultをhandleするOk(value)armでは、Sum: [value]をPrintするErr(_)armでは、Parsing errorをPrintする
入力:
- first line: numberを表す文字列(例:
15) - second line: 別のnumberを表す文字列(例:
27)
出力:
- 両方の文字列が有効なnumberの場合:
Sum: [result] - いずれかの文字列をparseできない場合:
Parsing error
自分で試してみよう
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]" を出力する
// Print "Parsing error" for Err(_)
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
論理とフローのすべてのレッスン
7'Result' によるエラーハンドリング
'Result' とは?'Result' で 'match' を使うis_ok() と is_err()ショートカット: unwrap と expectクエスチョンマーク演算子 '?'文字列から数値へのパースまとめ - 安全な除算関数自分で練習してみよう: Rustオンラインコンパイラ