常用結果方法
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
。