错误处理
1. pacnic
主动退出,类似exit(0),但是可以携带信息。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | fn give_princess(gift: &str) {
 if gift == "snake" { panic!("AAAaaaaa!!!!"); }
 println!("I love {}s!!!!!", gift);
 }
 
 fn main() {
 give_princess("teddy bear");
 give_princess("snake");
 }
 
 | 
2. unwrap
隐士解构Reuslt或Option。
a.unwrap()
| 12
 
 | let x: Result<u32, &str> = Ok(2);assert_eq!(x.unwrap(), 2);
 
 | 
b.unwrap_or_default()
| 12
 3
 4
 5
 6
 7
 
 | let good_year_from_input = "1909";let bad_year_from_input = "190blarg";
 let good_year = good_year_from_input.parse().unwrap_or_default();
 let bad_year = bad_year_from_input.parse().unwrap_or_default();
 
 assert_eq!(1909, good_year);
 assert_eq!(0, bad_year);
 
 | 
c.unwrap_or_else()
| 12
 3
 4
 
 | fn count(x: &str) -> usize { x.len() }
 assert_eq!(Ok(2).unwrap_or_else(count), 2);
 assert_eq!(Err("foo").unwrap_or_else(count), 3);
 
 | 
3. Option
3.1 介绍
在标准库(std)中有个叫做 Option<T>的枚举类型,用于处理含有 None出现的可能性 的情况。它表现为以下两个option中的一个:
- Some(T):找到一个属于- T类型的元素
- None:找不到相应元素
这些option可以通过 match 显式地处理,或使用 unwrap 隐式地处理。隐式处理如果遇到None就 panic,否则返回 Some 内部的元素。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | fn give_commoner(gift: Option<&str>) {match gift {
 Some("snake") => println!("Yuck! I'm throwing that snake in a fire."),
 
 Some(inner)   => println!("{}? How nice.", inner),
 None          => println!("No gift? Oh well."),
 }
 }
 
 fn give_princess(gift: Option<&str>) {
 
 let inside = gift.unwrap();
 if inside == "snake" { panic!("AAAaaaaa!!!!"); }
 println!("I love {}s!!!!!", inside);
 }
 
 fn main() {
 
 let bird = Some("robin");
 let nothing = None;
 
 give_princess(bird);
 give_princess(nothing);
 }
 
 | 
3.2 解构Option
Option可以通过?来解构,解构可以获得底层的值,但是?运算符必须在返回Option类型的函数中使用,并且如果要解构的对象是None,则函数直接返回None。例子如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | struct Person {job: Option<Job>,
 }
 
 #[derive(Clone, Copy)]
 struct Job {
 phone_number: Option<PhoneNumber>,
 }
 
 #[derive(Clone, Copy)]
 struct PhoneNumber {
 area_code: Option<u8>,
 number: u32,
 }
 
 impl Person {
 fn work_phone_area_code(&self) -> Option<u8> {
 
 self.job?.phone_number?.area_code
 }
 }
 
 | 
在main函数中使用?运算符解构,必须嵌套一层返回Option的函数,代码如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | fn test_opt() -> Option<u8> {let p = Person {
 job: Some(Job {
 phone_number: Some(PhoneNumber {
 area_code: Some(123),
 number: 439222222,
 }),
 }),
 };
 
 let opt_val = p.work_phone_area_code();
 
 let val = opt_val?;
 
 println!("Here {}", val);
 
 return opt_val
 }
 
 fn main() {
 test_opt();
 }
 
 | 
常规match解构,代码如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | fn main() {let p = Person {
 job: Some(Job {
 phone_number: Some(PhoneNumber {
 area_code: Some(5),
 number: 439222222,
 }),
 }),
 };
 
 let val = p.work_phone_area_code();
 match val {
 Some(5) => println!("val is right"),
 Some(v) => println!("val is {}", v),
 None => println!("empty.")
 }
 }
 
 | 
4 Result
Result是Option更丰富的版本,描述的是可能的错误,而不是可能的不存在。
也就是说,Result<T,E> 可以有两个结果的其中一个:
- Ok<T>:找到- T元素
- Err<E>:找到- E元素,- E即表示错误的类型。
按照约定,预期结果是 “Ok”,而意外结果是 “Err”。
Result也有unwrap()方法,如果存在错误,就panic,否则返回元素T。
Result还有个expect方法,用于在panic前打印信息。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | fn parse_i32_from_string(number_str: &str) -> i32 {let num = number_str.parse::<i32>().unwrap();
 num
 }
 
 fn main() {
 
 let num = parse_i32_from_string("dvdsf");
 
 let num = parse_i32_from_string("123");
 println!("{}", num);
 }
 
 | 
4.1 向上抛的错误
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | use std::num::ParseIntError;
 
 fn parse_i32_from_string(number_str: &str) -> Result<i32, ParseIntError> {
 match number_str.parse::<i32>() {
 Ok(num)  => Ok(num),
 Err(e) => Err(e),
 }
 }
 
 fn print(result: Result<i32, ParseIntError>) {
 match result {
 Ok(n)  => println!("n is {}", n),
 Err(e) => println!("Error: {}", e),
 }
 }
 
 fn main() {
 
 let num = parse_i32_from_string("123");
 print(num);
 }
 
 | 
4.2 为Result创建别名
| 12
 3
 
 | type AliasedResult<T> = Result<T, ParseIntError>;
 fn multiply(first_number_str: &str, second_number_str: &str) -> AliasedResult<i32> {
 
 | 
4.3 遇到错误提前返回
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | use std::num::ParseIntError;
 fn parse_i32_from_string(number_str: &str) -> Result<i32, ParseIntError> {
 match number_str.parse::<i32>() {
 Ok(num)  => Ok(num),
 Err(e) => return Err(e),
 }
 }
 
 fn print(result: Result<i32, ParseIntError>) {
 match result {
 Ok(n)  => println!("n is {}", n),
 Err(e) => println!("Error: {}", e),
 }
 }
 
 fn main() {
 
 let num = parse_i32_from_string("123");
 print(num);
 }
 
 | 
4.4 获取值而不panic的简便写法
| 12
 3
 4
 5
 6
 7
 
 | fn parse_i32_from_string(number_str: &str) -> Result<i32, ParseIntError> {
 let num = number_str.parse::<i32>()?;
 
 let num = try!(number_str.parse::<i32>());
 Ok(num)
 }
 
 | 
5. 多种错误类型处理
代码如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | fn double_first(vec: Vec<&str>) -> i32 {let first = vec.first().unwrap();
 2 * first.parse::<i32>().unwrap()
 }
 
 fn main() {
 let numbers = vec!["42", "93", "18"];
 let empty = vec![];
 let strings = vec!["tofu", "93", "18"];
 
 println!("The first doubled is {}", double_first(numbers));
 
 println!("The first doubled is {}", double_first(empty));
 
 
 println!("The first doubled is {}", double_first(strings));
 
 }
 
 | 
最常见的做法是将Option与Result互相包裹来处理:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | fn fouble_first(vec: Vec<&str>) -> Result<Option<i32>, ParseIntError> {let opt = match vec.first() {
 Some(v) => {
 match v.parse::<i32>() {
 Ok(n) => Some(Ok(n * 2)),
 Err(e) => Some(Err(e))
 }
 },
 None => None,
 };
 opt.map_or(Ok(None), |r| r.map(Some))
 }
 
 | 
6. anyhow使用
dtolnay/anyhow: Flexible concrete Error type built on std: :Error (github.com)
| 12
 3
 4
 5
 6
 7
 8
 
 | use anyhow::{Result, anyhow};
 fn test_fun(val: u64) -> Result<u64> {
 if val == 0 {
 return Err(anyhow!("args is 0."));
 }
 Ok(128)
 }
 
 |