?演算子はどこで使える?
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
にしてくれます。
たとえば...
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 を使って次のように書けます。
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