Result について

Result<T, E> という型が、std::result というモジュールに定義されています。

この型は、ファイルの入出力やオープンのような失敗する可能性のある関数の戻り型として使われます。

宣言は以下のような感じ。

enum Result<T, E> {
    Ok(T),
    Err(E)
}

enumなのでパターンマッチして使用するわけです。

たとえば、ファイルをオープンするのに、以下のようなコードを書きます。

use std::fs::File;


let mut file = match File::open("some.txt") {
    Ok(file) => {file}                           // Okなら、そのまま返す。
    Err(why) => {panic!(why.to_string())}        // 失敗時は、panicでプログラム終了
}

unwrap() : エラー時に panic を呼び出す。

いちいち match して Okの値を取り出すのは面倒なので、Okの値を取り出す unwrap() という関数があります。

let mut file = File::open("some.txt").unwrap();

file には、Ok(x) の x が代入されます。 open が Err(why) を返すと、unwrap() は why の値を表示してpanicします。

"{:?}"でフォーマットして出力するので、あまり見やすい表示とは言えませんが。

thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os(2) }', /home/rust/src/libcore/result.rs:729

ok().expect(パニック時の表示文字列)

why を捨てていいなら、Result<T,E>::ok() で Option に変換できるので、以下のように書けます。

let mut file = File::open("some.txt").ok().expect("open error");

この場合は、エラー原因である why を捨てているので、ファイルのオープンエラーが発生したことはわかりますが、その理由がわかりません。

try! マクロで早期リターン

try! マクロを使うとエラー時にはResultをリターンして、正常時には Ok の値を返します。

fn read_from(fname: &str) -> io::Result<String> {
    let mut s = String::new();
    let mut file = try!(File::open(fname));
    try!(file.read_to_string(& mut s));
    return Ok(s);
}

fn main() {
    match read_from("some.txt") {
        Ok(s) => {println!("{}", s);
        Err(why) => {println!("{}", whly.to_string())}
    };
}

その他の関数

Result<T, E>には、他にも以下の関数があります。

and(res: Result<U,E>) -> Result<U, E> - Ok 時には、resを返す。Err時には selfを返す。

and_then(処理) - Ok時には、Ok値を引数に処理を実行し、Err時には、Err(why) を返す。

or(res: Result<U, E>) - Ok時には、selfを、Err時には、resを返す。

or_else(処理) - Err 時にはErr値を引数にとる処理を実行し、Ok 時にはResultのまま返す。

unwrap_or(opt:T) - Err 時には opt を返す。

unwrap_or_else(処理) - 返り値が、Resultではなくて、Tになる。

unwrap_err - Errの値を返す。Okの場合は、panicする。

使用例

use std::fs::File;
use std::io;
use std::io::Read;

fn read_from(fname: & str) -> io::Result<String> {
    return File::open(fname).and_then(|mut file| {
        let mut s = String::new();
        //try!(file.read_to_string(& mut s));
        //return Ok(s);
        return file.read_to_string(& mut s).and(Ok(s));
    });
}

fn main() {
    match read_from("unwrap.rs") {
        Ok(s) => {println!("{}", s)}
        Err(why) => {println!("{}", why.to_string())}
    };
}