[−][src]Function tao_of_rust::ch09::errors::error_handle
pub fn error_handle()
分层错误处理
- Option
- Error
- Panic
- Abort
Base usage: 使用Option
fn get_shortest(names: Vec<&str>) -> Option<&str> { if names.len() > 0 { let mut shortest = names[0]; for name in names.iter() { if name.len() < shortest.len() { shortest = *name; } } Some(shortest) } else { None } } fn show_shortest(names: Vec<&str>) -> &str { match get_shortest(names) { Some(shortest) => shortest, None => "Not Found", } } fn main(){ assert_eq!(show_shortest(vec!["Uku", "Felipe"]), "Uku"); assert_eq!(show_shortest(Vec::new()), "Not Found"); }Run
Base usage: 高效处理Option
fn get_shortest_length(names: Vec<&str>) -> Option<usize> { match get_shortest(names) { Some(shortest) => Some(shortest.len()), None => None, } } fn main(){ assert_eq!(get_shortest_length(vec!["Uku","Felipe"]),Some(3)); assert_eq!(get_shortest_length(Vec::new()), None); }Run
Base usage: 使用map处理Option
fn get_shortest_length(names: Vec<&str>) -> Option<usize> { get_shortest(names).map(|name| name.len()) } fn main(){ assert_eq!(get_shortest_length(vec!["Uku","Felipe"]),Some(3)); assert_eq!(get_shortest_length(Vec::new()), None); }Run
Base usage: 使用map和and_than处理Option
fn double(value: f64) -> f64 { value * 2. } fn square(value: f64) -> f64 { value.powi(2 as i32) } fn inverse(value: f64) -> f64 { value * -1. } fn log(value: f64) -> Option<f64> { match value.log2() { x if x.is_normal() => Some(x), _ => None } } fn sqrt(value: f64) -> Option<f64> { match value.sqrt() { x if x.is_normal() => Some(x), _ => None } } fn main () { let number: f64 = 20.; let result = Option::from(number) .map(inverse).map(double).map(inverse) .and_then(log).map(square).and_then(sqrt); match result { Some(x) => println!("Result was {}.", x), None => println!("This failed.") } }Run
Base usage: 处理Result<T, E>
fn main(){ let n = "1"; assert_eq!(n.parse::<i32>(), Ok(1)); let n = "a"; // 输出 Err(ParseIntError { kind: InvalidDigit }) println!("{:?}", n.parse::<i32>()); }Run
Base usage: 使用map处理Result<T, E>
use std::num::ParseIntError; // fn square(number_str: &str) -> Result<i32, ParseIntError> // { // number_str.parse::<i32>().map(|n| n.pow(2)) // } type ParseResult<T> = Result<T, ParseIntError>; fn square(number_str: &str) -> ParseResult<i32> { number_str.parse::<i32>().map(|n| n.pow(2)) } fn main() { match square("10") { Ok(n) => assert_eq!(n, 100), Err(err) => println!("Error: {:?}", err), } }Run
Base usage: 从文件中读取数字并计算求和,展示统一的错误处理
将此代码复制到自定义的io_origin.rs文件里,rustc编译之后在终端执行命令:
$ ./io_origin test_txt
use std::env; use std::fs::File; use std::io::prelude::*; fn main() { let args: Vec<String> = env::args().collect(); println!("{:?}", args); let filename = &args[1]; let mut f = File::open(filename).unwrap(); let mut contents = String::new(); f.read_to_string(&mut contents).unwrap(); let mut sum = 0; for c in contents.lines(){ let n = c.parse::<i32>().unwrap(); sum += n; } println!("{:?}", sum); }Run
Base usage: 【重构】从文件中读取数字并计算求和,展示统一的错误处理
将此代码复制到自定义的io_origin.rs文件里,rustc编译之后在终端执行命令:
$ ./io_origin test_txt
use std::env; use std::error::Error; use std::fs::File; use std::io::prelude::*; use std::process; type ParseResult<i32> = Result<i32, Box<Error>>; fn run(filename: &str) -> ParseResult<i32> { File::open(filename).map_err(|e| e.into()) .and_then(|mut f|{ let mut contents = String::new(); f.read_to_string(&mut contents) .map_err(|e| e.into()).map(|_|contents) }) .and_then(|contents|{ let mut sum = 0; for c in contents.lines(){ match c.parse::<i32>() { Ok(n) => {sum += n;}, Err(err) => { let err: Box<Error> = err.into(); println!("error info: {}, cause: {:?}" , err.description(),err.cause()); }, // Err(err) => { return Err(From::from(err));}, } } Ok(sum) }) } fn main() { let args: Vec<String> = env::args().collect(); let filename = &args[1]; println!("In file {}", filename); match run(filename) { Ok(n) => { println!("{:?}", n); }, Err(e) => { println!("main error: {}", e); process::exit(1); } } }Run
Base usage: 【再次重构】从文件中读取数字并计算求和,展示统一的错误处理
动态分发改为静态分发
将此代码复制到自定义的io_origin.rs文件里,rustc编译之后在终端执行命令:
$ ./io_origin test_txt
use std::env; use std::error::Error; use std::fs::File; use std::io::prelude::*; use std::process; use std::io; use std::num; use std::fmt; #[derive(Debug)] enum CliError { Io(io::Error), Parse(num::ParseIntError), } impl fmt::Display for CliError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CliError::Io(ref err) => write!(f, "IO error: {}", err), CliError::Parse(ref err) => write!(f, "Parse error: {}", err), } } } impl Error for CliError { fn description(&self) -> &str { match *self { CliError::Io(ref err) => err.description(), CliError::Parse(ref err) => Error::description(err), } } fn cause(&self) -> Option<&Error> { match *self { CliError::Io(ref err) => Some(err), CliError::Parse(ref err) => Some(err), } } } impl From<io::Error> for CliError { fn from(err: io::Error) -> CliError { CliError::Io(err) } } impl From<num::ParseIntError> for CliError { fn from(err: num::ParseIntError) -> CliError { CliError::Parse(err) } } fn run(filename: Option<String>) -> ParseResult<i32> { let mut file = File::open(filename.unwrap())?; let mut contents = String::new(); file.read_to_string(&mut contents)?; let mut sum = 0; for c in contents.lines(){ let n: i32 = c.parse::<i32>()?; sum += n; } Ok(sum) } type ParseResult<i32> = Result<i32, CliError>; fn main() { let filename = env::args().nth(1); match run(filename) { Ok(n) => { println!("{:?}", n); }, Err(e) => { println!("main error: {}", e); process::exit(1); } } }Run
Base usage: 【三次重构】从文件中读取数字并计算求和,展示统一的错误处理
使用try!的简化问号操作符
将此代码复制到自定义的io_origin.rs文件里,rustc编译之后在终端执行命令:
$ ./io_origin test_txt
use std::env; use std::error::Error; use std::fs::File; use std::io::prelude::*; use std::process; use std::io; use std::num; use std::fmt; #[derive(Debug)] enum CliError { Io(io::Error), Parse(num::ParseIntError), } impl fmt::Display for CliError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CliError::Io(ref err) => write!(f, "IO error: {}", err), CliError::Parse(ref err) => write!(f, "Parse error: {}", err), } } } impl Error for CliError { fn description(&self) -> &str { match *self { CliError::Io(ref err) => err.description(), CliError::Parse(ref err) => Error::description(err), } } fn cause(&self) -> Option<&Error> { match *self { CliError::Io(ref err) => Some(err), CliError::Parse(ref err) => Some(err), } } } impl From<io::Error> for CliError { fn from(err: io::Error) -> CliError { CliError::Io(err) } } impl From<num::ParseIntError> for CliError { fn from(err: num::ParseIntError) -> CliError { CliError::Parse(err) } } fn run(filename: &str) -> ParseResult<i32> { let mut file = File::open(filename)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; let mut sum = 0; for c in contents.lines(){ let n: i32 = c.parse::<i32>()?; sum += n; } Ok(sum) } type ParseResult<i32> = Result<i32, CliError>; fn main() { let args: Vec<String> = env::args().collect(); let filename = &args[1]; println!("In file {}", filename); match run(filename) { Ok(n) => { println!("{:?}", n); }, Err(e) => { println!("main error: {}", e); process::exit(1); } } }Run
Base usage: 【四次重构】从文件中读取数字并计算求和,展示统一的错误处理
使用NoneError
将此代码复制到自定义的io_origin.rs文件里,rustc编译之后在终端执行命令:
$ ./io_origin test_txt
#![feature(try_trait)] use std::env; use std::error::Error; use std::fs::File; use std::io::prelude::*; use std::process; use std::io; use std::num; use std::fmt; use std::option::NoneError; #[derive(Debug)] enum CliError { Io(io::Error), Parse(num::ParseIntError), NoneError(NoneError), } impl fmt::Display for CliError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CliError::Io(ref err) => write!(f, "IO error: {}", err), CliError::Parse(ref err) => write!(f, "Parse error: {}", err), CliError::NoneError(ref err) => write!(f, "Command args error: {:?}", err), } } } impl Error for CliError { fn description(&self) -> &str { match *self { CliError::Io(ref err) => err.description(), CliError::Parse(ref err) => Error::description(err), CliError::NoneError(ref err) => "NoneError", } } fn cause(&self) -> Option<&Error> { match *self { CliError::Io(ref err) => Some(err), CliError::Parse(ref err) => Some(err), _ => None, } } } impl From<io::Error> for CliError { fn from(err: io::Error) -> CliError { CliError::Io(err) } } impl From<NoneError> for CliError { fn from(err: NoneError) -> CliError { CliError::NoneError(err) } } impl From<num::ParseIntError> for CliError { fn from(err: num::ParseIntError) -> CliError { CliError::Parse(err) } } fn run(filename: Option<String>) -> ParseResult<i32> { let mut file = File::open(filename?)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; let mut sum = 0; for c in contents.lines(){ let n: i32 = c.parse::<i32>()?; sum += n; } Ok(sum) } type ParseResult<i32> = Result<i32, CliError>; fn main() { let filename = env::args().nth(1); match run(filename) { Ok(n) => { println!("{:?}", n); }, Err(e) => { eprintln!("main error: {}", e); process::exit(1); } } }Run