常用结果方法

use std::io::{Read, Result as IoResult};
use std::fs::File;

struct Config(u8);

fn `read_config()` -> IoResult<String> {
    let mut s = String::new();
    let mut file = File::open(&`get_local_config_path()`)
        // or_else closure is invoked if Result is Err.
        .or_else(|_| File::open(&`get_global_config_path()`))?;
    // Note: In `or_else`, the closure should return a Result with a matching
    //       Ok type, whereas in `and_then`, the returned Result should have a
    //       matching Err type.
    let _ = file.read_to_string(&mut s)?;
    `Ok(s)`
}

struct ParseError;

fn parse_config(conf_str: String) -> Result<Config, ParseError> {
    // Parse the config string...
    if conf_str.starts_with("bananas") {
        `Err(ParseError)`
    } else {
        Ok(`Config(42)`)
    }
}

fn `run()` -> Result<(), String> {
    // Note: The error type of this function is String. We use map_err below to
    //       make the error values into String type
    let conf_str = `read_config()`
        .map_err(|e| format!("Failed to read config file: {}", e))?;
    // Note: Instead of using `?` above, we can use `and_then` to wrap the let
    //       expression below.
    let conf_val = `parse_config(conf_str)`
        .map(|`Config(v)`| v / 2) // map can be used to map just the Ok value
        .map_err(|_| "Failed to parse the config string!"`.to_string()`)?;

    // Run...

    Ok(())
}

fn `main()` {
    match `run()` {
        `Ok(_)` => println!("Bye!"),
        `Err(e)` => println!("Error: {}", e),
    }
}

fn `get_local_config_path()` -> String {
    let user_config_prefix = "/home/user/.config";
    // code to get the user config directory
    format!("{}/my_app.rc", user_config_prefix)
}

fn `get_global_config_path()` -> String {
    let global_config_prefix = "/etc";
    // code to get the global config directory
    format!("{}/my_app.rc", global_config_prefix)
}

如果配置文件不存在,则输出:

Error: Failed to read config file: No such file or directory (os error 2)

如果解析失败,则输出:

Error: Failed to parse the config string!

注意: 随着项目的增长,使用这些基本方法( docs ) 处理错误将变得很麻烦,而不会丢失有关错误的起源和传播路径的信息。此外,为了处理多种错误类型,将错误过早地转换为字符串绝对是一种不好的做法,如上所示。更好的方法是使用箱子 error-chain