Menu
Coddy logo textTech

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

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 を返した場合は、? は即座にそのエラーを関数全体から返します。

::<i32> 構文に注目してください。これは ターボフィッシュ と呼ばれ、文字列をどの型にパースするかを Rust に伝えます。この関数は Result<i32, std::num::ParseIntError> を返します。ここで i32 は成功時の型であり、std::num::ParseIntError はパースに失敗したときに返されるエラー型です。

? 演算子は、エラーを返す必要があるため、Result(または Option)を返す関数内でのみ使用できます。

challenge icon

チャレンジ

簡単

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

自分で試してみよう

use std::io;

// TODO: ここに add_numbers 関数を作成します
// 2つの &str パラメータを受け取り、Result<i32, std::num::ParseIntError> を返す必要があります


fn main() {
    // 1つ目の入力を読み取ります
    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" を出力します
}
quiz icon腕試し

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

Logic & Flowのすべてのレッスン