核心概念
Error错误处理
Error Handling with:Result, Option & panic! macro
Error Type in Rust
Rust中的错误可以分为两种:
Recoverable error: 有返回类型
- 返回Result类型
- 返回Option类型
Unrecoverable type: 没有返回类型,直接崩溃
panic macro将终止当前线程
Result
Result是一个枚举类型,有两个变体:ok和Err。它通常用于表示函数的执行结果,其中ok表示成功的结果,Err表示出现了错误:
pub enum Result<T,E> {Ok(T),Err(E),}
Option
Option也是一个枚举类型,有两个变体:Some和None。它通常用于表示一个可能为空的值。
pub enum Option<T> {None,Some(T),}
panic!
- 当程序遇到无法继续执行的错误时,可以使用
panic!宏来引发恐慌。恐慌会导致程序立即终止,并显示一条错误信息。
Example
定义两个函数分别为divide和find_element,
fn divide(a: i32, b: i32) -> Result<f64, String> {if b == 0 {return Err(String::from("cannot be zero"));}let a = a as f64;let b = b as f64;Ok(a / b)}fn find_element(array: &[i32], target: i32) -> Option<usize> {for (index, elem) in array.iter().enumerate() {if (*elem) == target {return Some(index);}}None}fn main() {// resultmatch divide(1, 2) {Ok(number) => println!("{}", number), // 0.5Err(err) => println!("{}", err),}match divide(1, 0) {Ok(number) => println!("{}", number),Err(err) => println!("{}", err), // cannot be zero}// optionlet arr = [1, 2, 3, 4, 5];match find_element(&arr, 4) {Some(index) => println!("found in {}", index), // found in 3None => println!("None"),}match find_element(&arr, 7) {Some(index) => println!("found in {}", index),None => println!("None"), // None}// paniclet vec = vec![1, 2, 3, 4, 5];vec[43];}
Error Handling with:unwrap() & ?
unwrap()
unwrap()是Result和Option类型提供的方法之一。它是一个简便的方法,用于获取Ok或Some的值,如果是Err或None则会引发panic。
提示
该方法并不安全。
? Operator
?用于简化Result或Option类型的错误传播。它只能用于返回Result或Option的函数中,并且在函数内部可以像使用unwrap()一样访问Ok或Some的值,但是如果是Err或None则会提前返回。
Example
1use std::num::ParseIntError;23fn find_first_even(numbers: Vec<i32>) -> Option<i32> {4 let first_even = numbers.iter().find(|&num| num % 2 == 0)?; // 使用?运算符前提条件是需要返回Option类型5 Some(*first_even)6}78// 传递错误9fn parse_numbers(input: &str) -> Result<i32, ParseIntError> {10 let val = input.parse::<i32>()?; // 使用?运算符如果发现error将提前返回11 Ok(val)12}131415fn main() -> Result<(), Box<dyn std::error::Error>> {16 let result_ok: Result<i32, &str> = Ok(32);17 let value = result_ok.unwrap();18 println!("{}", value); // 321920 let result_ok: Result<i32, &str> = Ok(32);21 let value = result_ok?;22 println!("{}", value); // 322324 let numbers = vec![1, 2, 3, 4, 5];25 match find_first_even(numbers) {26 Some(number) => println!("first even {}", number), // first even 227 None => println!("no such number"),28 }2930 match parse_numbers("d") {31 Ok(i) => println!("parsed {}", i),32 Err(err) => println!("failed to parse: {}", err), // failed to parse: invalid digit found in string33 }3435 Ok(())36}
Customize an Error Type
自定义Error类型的三个步骤:
- 定义错误类型结构体:创建一个结构体来表示你的错误类型,通常包含一些字段来描述错误的详细信息。
- 实现
std::fmt::Display trait:实现这个trait以定义如何展示错误信息。这是为了使错误能够以人类可读的方式打印出来。 - 实现
std::error::Error trait:实现这个trait以满足Rust的错误处理机制的要求。
1use std::fmt::write;23#[derive(Debug)]4struct MyError {5 detail: String,6}78impl std::fmt::Display for MyError {9 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {10 write!(f, "Custom Error: {}", self.detail)11 }12}1314impl std::error::Error for MyError {15 fn description(&self) -> &str {16 &self.detail17 }18 // &String => &str 字符串引用自动转换成字符串字面量19}2021fn func_err() -> Result<(), MyError> {22 Err(MyError{23 detail: "Custom Error".to_owned(),24 })25}2627fn func_ok() -> Result<(), MyError> {28 Ok(())29}3031fn main() -> Result<(), MyError> {32 match func_ok() {33 Ok(_) => println!("func ok"),34 Err(err) => println!("Error: {}", err),35 }36 func_ok()?;37 println!("ok");38 match func_err() {39 Ok(_) => println!("func ok"),40 Err(err) => println!("Error: {}", err),41 }42 func_err()?;43 println!("oo");44 Ok(())45}4647// fn main() -> Result<(), Box<dyn std::error::Error>> {48// match func() {49// Ok(_) => println!("func ok"),50// Err(err) => println!("Error: {}", err),51// }52// func()?;53// println!("oo");54// Ok(())55// }