Rust 通用结果方法
示例
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()) //如果Result为Err,则调用or_else闭包。 .or_else(|_| File::open(&get_global_config_path()))?; //注意:在`or_else`中,闭包应该返回带有匹配项的Result //确定类型,而在`and_then`中,返回的Result应该有一个 //匹配的Err类型。 let _ = file.read_to_string(&mut s)?; Ok(s) } struct ParseError; fn parse_config(conf_str: String) -> Result<Config, ParseError> { //解析配置字符串... if conf_str.starts_with("bananas") { Err(ParseError) } else { Ok(Config(42)) } } fn run() -> Result<(), String> { //注意:此函数的错误类型为字符串。我们使用下面的map_err //将错误值转换为String类型 let conf_str = read_config() .map_err(|e| format!("Failed to read config file: {}", e))?; //注意:我们可以使用`and_then`来包装let而不是上面的`?`。 //表达式如下。 let conf_val = parse_config(conf_str) .map(|Config(v)| v / 2) //map可用于仅映射Ok值 .map_err(|_| "无法解析配置字符串!".to_string())?; //跑... 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"; //获取用户配置目录的代码 format!("{}/my_app.rc", user_config_prefix) } fn get_global_config_path() -> String { let global_config_prefix = "/etc"; //获取全局配置目录的代码 format!("{}/my_app.rc", global_config_prefix) }
如果配置文件不存在,则输出:
Error: Failed to read config file: No such file or directory (os error 2)
如果解析失败,则输出:
Error: 无法解析配置字符串!
注意:随着项目的发展,使用这些基本方法(文档)来处理错误会很麻烦,而又不会丢失有关错误的来源和传播路径的信息。同样,过早地将错误转换为字符串以处理多种错误类型绝对是一个坏习惯,如上所述。更好的方法是使用板条箱error-chain。