目录
可恢复的错误 Result
unwrap/expect 如果失败就panic
use std::fs::File; fn main() { // 如果调用这段代码时 hello.txt 文件不存在,那么 unwrap 就将直接 panic let f = File::open("hello.txt").unwrap(); }
?
和报错传播
fn open_file() -> Result<File, Box<dyn std::error::Error>> { // 如果失败就自动return Err let mut f = File::open("hello.txt")?; Ok(f) }
?
不仅仅可以用于 Result
的传播,还能用于 Option
的传播
fn last_char_of_first_line(text: &str) -> Option<char> { text.lines().next()?.chars().last() }
新手用 ?
常会犯的错误
初学者在用 ?
时,老是会犯错,例如写出这样的代码:
fn first(arr: &[i32]) -> Option<&i32> { arr.get(0)? }
切记:?
操作符需要一个变量来承载正确的值,这个函数只会返回 Some(&i32)
或者 None
,然而只有错误值能直接返回,正确的值不行
实际上 Rust 还支持另外一种形式的 main 函数
use std::error::Error; use std::fs::File; fn main() -> Result<(), Box<dyn Error>> { let f = File::open("hello.txt")?; Ok(()) }
例子
1
use std::num::ParseIntError; fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { let n1 = n1_str.parse::<i32>(); let n2 = n2_str.parse::<i32>(); Ok(n1.unwrap() * n2.unwrap()) } fn main() { let result = multiply("10", "2"); assert_eq!(result, Ok(20)); let result = multiply("4", "2"); assert_eq!(result.unwrap(), 8); println!("Success!") }
用?
改写
use std::num::ParseIntError; // IMPLEMENT multiply with ? // DON'T use unwrap here fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { let n1 = n1_str.parse::<i32>()?; let n2 = n2_str.parse::<i32>()?; Ok(n1 * n2) } fn main() { assert_eq!(multiply("3", "4").unwrap(), 12); println!("Success!") }
连续?
use std::fs::File; use std::io::{self, Read}; fn read_file1() -> Result<String, io::Error> { let f = File::open("hello.txt"); let mut f = match f { Ok(file) => file, Err(e) => return Err(e), }; let mut s = String::new(); match f.read_to_string(&mut s) { Ok(_) => Ok(s), Err(e) => Err(e), } } fn read_file2() -> Result<String, io::Error> { let mut s = String::new(); // 注意 read_to_string(&mut s)?的?虽然不写也可以通过,但是就错过了可能报的错 File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) } fn main() { assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string()); println!("Success!") }
map
和and_then
的使用
use std::num::ParseIntError; fn add_two(n_str: &str) -> Result<i32, ParseIntError> { n_str.parse::<i32>().map(|num| num +2) } fn main() { assert_eq!(add_two("4").unwrap(), 6); println!("Success!") }
use std::num::ParseIntError; fn add_two(n_str: &str) -> Result<i32, ParseIntError> { n_str.parse::<i32>().and_then(|num| Ok(num +2)) } fn main() { assert_eq!(add_two("4").unwrap(), 6); println!("Success!") }
用map
/and_then
改写
use std::num::ParseIntError; // With the return type rewritten, we use pattern matching without `unwrap()`. // But it's so Verbose.. fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { match n1_str.parse::<i32>() { Ok(n1) => { match n2_str.parse::<i32>() { Ok(n2) => { Ok(n1 * n2) }, Err(e) => Err(e), } }, Err(e) => Err(e), } } // Rewriting `multiply` to make it succinct // You MUST USING `and_then` and `map` here fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> { // IMPLEMENT... n1_str.parse::<i32>().and_then(|n1| { n2_str.parse::<i32>().map(|n2| n1 * n2) }) } fn print(result: Result<i32, ParseIntError>) { match result { Ok(n) => println!("n is {}", n), Err(e) => println!("Error: {}", e), } } fn main() { // This still presents a reasonable answer. let twenty = multiply1("10", "2"); print(twenty); // The following now provides a much more helpful error message. let tt = multiply("t", "2"); print(tt); println!("Success!") }
简化类型
use std::num::ParseIntError; // Define a generic alias for a `Result` with the error type `ParseIntError`. type Res<T> = Result<T, ParseIntError>; // Use the above alias to refer to our specific `Result` type. fn multiply(first_number_str: &str, second_number_str: &str) -> Res<i32> { first_number_str.parse::<i32>().and_then(|first_number| { second_number_str.parse::<i32>().map(|second_number| first_number * second_number) }) } // Here, the alias again allows us to save some space. fn print(result: Res<i32>) { match result { Ok(n) => println!("n is {}", n), Err(e) => println!("Error: {}", e), } } fn main() { print(multiply("10", "2")); print(multiply("t", "2")); }
main里的return问题
原题如果改成用特征对象就会报错
use std::num::ParseIntError; fn main() -> Result<(), Box<dyn std::error::Error>> { let number_str = "10"; let number = match number_str.parse::<i32>() { Ok(number) => number, Err(e) => return Err(e), }; println!("{}", number); Ok(()) }
用?
就成功,这是为什么呢?不是说?
是个宏,其实也是return了Err(e)的吗?
use std::num::ParseIntError; fn main() -> Result<(), Box<dyn std::error::Error>> { let number_str = "10"; let number = number_str.parse::<i32>()?; println!("{}", number); Ok(()) }