Menu
Coddy logo textTech

クエスチョンマーク演算子 '?'

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)を返す関数でのみ使用できます。

challenge icon

チャレンジ

簡単

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つの&str parametersを受け取り、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する
  • match expressionを使用して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&lt;i32, std::num::ParseIntError&gt; を返す必要があります


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(_)
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

論理とフローのすべてのレッスン

自分で練習してみよう: Rustオンラインコンパイラ