LoginSignup
40
17

More than 3 years have passed since last update.

Rustの?演算子

Last updated at Posted at 2018-11-04

?演算子はどこで使える?

rustの?演算子(question mark operator)はどこで使えるのか、という話です。
resultを返すにメソッド等に対して呼べる、と盛大な勘違いをしていたのですが、それに加えて大切なことがありました。
Resultを返す関数内でしか使えない、ということです。

The ? operator can only be used in functions that have a return type of Result

The ? Operator Can Only Be Used in Functions That Return Result

?演算子の働きを考えれば当然ですが、?演算子はErrをうけとったときに、関数の戻り値をErrにしてくれます。

たとえば...

sample.rs
use std::io;
use std::io::Read;
use std::fs::File;

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

チュートリアルの例ですが、read_username_from_file内部でErrが生じたときに、read_username_from_fileがそのErrを返すということです。Propagating Errorsと言われる所以でもあるでしょう。
したがって、?演算子はResultを戻り値とする関数内でしか使えません。

ということはmain関数内では使えないということです。
コメントでご指摘いただきまて、main関数もResultを返すことができるようになっています。(https://doc.rust-lang.org/std/fs/struct.File.html#examples)
またOptionを返すことも可能です。(https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1220-2017-11-22)
コメント欄にはサンプルコードも載せていただいております。どちらも問題なく動作しました。ありがとうございます。
とあるサンプルコードをmain関数に貼り付けてコンパイルしようとしたら怒られて知りました。(チュートリアルやったはずなのに...。)

複数の Error type を返す可能性がある場合

2つ以上の Error type が返る場合、Result<T, E>とはかけません。
そのような場合は trait object を使って次のように書けます。

multi_error.rs
use std::error::Error;
use std::fs::File;

fn main() -> Result<(), Box<dyn Error>> {
    let f = File::open("hello.txt")?;

    Ok(())
}

Recoverable Errors with Result - The Rust Programming Language

参考

A Shortcut for Propagating Errors: the ? Operator
main can return Result

40
17
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
17