panic 是 Rust 提供的异常处理机制,它打印 error message,然后开始 unwinding stack,最后退出当前thread:如果是 main thread panic,则整个程序退出,否则,如果是子线程 panic,则终止该子线程,程序不退出。
unwinding stack
过程中,Rust 会回溯调用栈,drop 所有的对象和资源,默认不打印调用栈,需要指定RUST_BACKTRACE=1 cargo run 来打印回溯的调用栈。
fn drink(beverage: &str) {
if beverage == "lemonade" { panic!("AAAaaaaa!!!!"); }
println!("Some refreshing {} is all I need.", beverage);
}
fn main() {
drink("water");
drink("lemonade");
drink("still water");
}
panic 时是 unwind(默认)还是 abort,可以配置:
- 在
.cargo/config.toml
的profile.dev
中配置为 abort: - 通过 cargo build 或 rustc 的
-C panic=abort/unwind
参数来配置:rustc lemonade.rs -C panic=abort
[profile.dev]
panic = 'unwind' # unwind 或 abort
对于设置的 panic 行为,代码可以使用 #[cfg(panic = "xx")]
来进行条件编译,使用 cfg!()
来进行条件判断:
// 根据 panic 设置进行条件编译
#[cfg(panic = "unwind")]
fn ah() {
println!("Spit it out!!!!");
}
#[cfg(not(panic = "unwind"))]
fn ah() {
println!("This is not your party. Run!!!!");
}
Option/Result
是泛型 enum 类型,支持迭代(效果就如 0 个或 1 个元素),支持 ? 操作符:
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 // 表达式中间使用 ?, 任何 None 结果都会提前返回 None
}
}
fn main() {
let p = Person {
job: Some(Job {
phone_number: Some(PhoneNumber {
area_code: Some(61),
number: 439222222,
}),
}),
};
assert_eq!(p.work_phone_area_code(), Some(61));
}
1 Option #
Option<T> 是泛型 enum 类型。
常用方法:
- XX_or(): 为 None 时使用传入的值;
- XX_or_else(): 为 None 时使用传入的闭包函数;
- XX_or_default() : 为 None 时使用缺省值;
pub const fn is_some(&self) -> bool
pub const fn is_none(&self) -> bool
pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool
let x: Option<u32> = Some(2);
assert_eq!(x.is_some_and(|x| x > 1), true);
let x: Option<u32> = Some(0);
assert_eq!(x.is_some_and(|x| x > 1), false);
// 从 &Option<T> 转换为 Option<&T>,这样后续处理时不转移 T 所有权
pub const fn as_ref(&self) -> Option<&T>
pub fn as_mut(&mut self) -> Option<&mut T>
pub fn as_pin_ref(self: Pin<&Option<T>>) -> Option<Pin<&T>>
pub fn as_pin_mut(self: Pin<&mut Option<T>>) -> Option<Pin<&mut T>>
let text: Option<String> = Some("Hello, world!".to_string());
let text_length: Option<usize> = text.as_ref().map(|s| s.len());
let mut x = Some(2);
match x.as_mut() {
Some(v) => *v = 42,
None => {},
}
assert_eq!(x, Some(42));
// 返回 slice,包含对应的 Some 元素,如果为 None 则返回空 slice
pub fn as_slice(&self) -> &[T]
pub fn as_mut_slice(&mut self) -> &mut [T]
assert_eq!(
[Some(1234).as_slice(), None.as_slice()],
[&[1234][..], &[][..]],
);
// 返回 Some 的 T 值,如果是 None 则 panic 并打印 msg (不支持格式化)
pub fn expect(self, msg: &str) -> T
// 返回 Some 的 T 值,如果是 None 则 panic
pub fn unwrap(self) -> T
// 返回 Some 的 T 值 ,如果是 None 则使用缺省值或闭包函数的返回值
pub fn unwrap_or(self, default: T) -> T
pub fn unwrap_or_else<F>(self, f: F) -> T where F: FnOnce() -> T
pub fn unwrap_or_default(self) -> T where T: Default
pub unsafe fn unwrap_unchecked(self) -> T
// 将 Option<T> 转换为 Option<U>, 如果为 None 则返回 None
pub fn map<U, F>(self, f: F) -> Option<U> where F: FnOnce(T) -> U
let maybe_some_string = Some(String::from("Hello, World!"));
let maybe_some_len = maybe_some_string.map(|s| s.len());
assert_eq!(maybe_some_len, Some(13));
let x: Option<&str> = None;
assert_eq!(x.map(|s| s.len()), None);
pub fn inspect<F>(self, f: F) -> Option<T> where F: FnOnce(&T)
let v = vec![1, 2, 3, 4, 5];
let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {x}")); // prints "got: 4"
let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {x}")); // prints nothing
// 返回 U 值:如果为 None 则返回 default 值, 否则对 Some 值执行 f 函数
pub fn map_or<U, F>(self, default: U, f: F) -> U where F: FnOnce(T) -> U
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U where D: FnOnce() -> U, F: FnOnce(T) -> U
let x = Some("foo");
assert_eq!(x.map_or(42, |v| v.len()), 3);
let x: Option<&str> = None;
assert_eq!(x.map_or(42, |v| v.len()), 42);
// 将 Option 转换为 Result: Some(v) -> Ok(v), None -> Err(err)
pub fn ok_or<E>(self, err: E) -> Result<T, E>
pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E> where F: FnOnce() -> E
let x = Some("foo");
assert_eq!(x.ok_or(0), Ok("foo"));
let x: Option<&str> = None;
assert_eq!(x.ok_or(0), Err(0));
pub fn as_deref(&self) -> Option<&<T as Deref>::Target> where T: Deref
pub fn as_deref_mut(&mut self) -> Option<&mut <T as Deref>::Target> where T: DerefMut
// Option 也支持迭代
pub fn iter(&self) -> Iter<'_, T>
pub fn iter_mut(&mut self) -> IterMut<'_, T>
let x = Some(4);
assert_eq!(x.iter().next(), Some(&4));
let x: Option<u32> = None;
assert_eq!(x.iter().next(), None);
// 如果 self 是 None 则返回 None, 否则返回 optb
pub fn and<U>(self, optb: Option<U>) -> Option<U>
let x = Some(2);
let y: Option<&str> = None;
assert_eq!(x.and(y), None);
let x: Option<u32> = None;
let y = Some("foo");
assert_eq!(x.and(y), None);
let x = Some(2);
let y = Some("foo");
assert_eq!(x.and(y), Some("foo"));
let x: Option<u32> = None;
let y: Option<&str> = None;
assert_eq!(x.and(y), None);
// 如果 self 是 None 则返回 None, 否则返回 f 函数的结果
pub fn and_then<U, F>(self, f: F) -> Option<U> where F: FnOnce(T) -> Option<U>
fn sq_then_to_string(x: u32) -> Option<String> {
x.checked_mul(x).map(|sq| sq.to_string())
}
assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
assert_eq!(None.and_then(sq_then_to_string), None);
// 如果 self 是 None 则返回 None, 否则如果 predicate 返回 true 则返回 Some
pub fn filter<P>(self, predicate: P) -> Option<T> where P: FnOnce(&T) -> bool
fn is_even(n: &i32) -> bool { n % 2 == 0 }
assert_eq!(None.filter(is_even), None);
assert_eq!(Some(3).filter(is_even), None);
assert_eq!(Some(4).filter(is_even), Some(4));
pub fn or(self, optb: Option<T>) -> Option<T>
pub fn or_else<F>(self, f: F) -> Option<T> where F: FnOnce() -> Option<T>
pub fn xor(self, optb: Option<T>) -> Option<T>
let x = None;
let y = Some(100);
assert_eq!(x.or(y), Some(100));
let x = Some(2);
let y = Some(100);
assert_eq!(x.or(y), Some(2));
let x: Option<u32> = None;
let y = None;
assert_eq!(x.or(y), None);
// 将 value 插入 Option 返回它的 &mut, Option 原来值被 dropped
pub fn insert(&mut self, value: T) -> &mut T
let mut opt = None;
let val = opt.insert(1);
assert_eq!(*val, 1);
assert_eq!(opt.unwrap(), 1);
let val = opt.insert(2);
assert_eq!(*val, 2);
*val = 3;
assert_eq!(opt.unwrap(), 3);
// 返回 Some 值的 &mut, 否则插入 value 并返回它的 &mut
pub fn get_or_insert(&mut self, value: T) -> &mut T
pub fn get_or_insert_default(&mut self) -> &mut T where T: Default
pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T where F: FnOnce() -> T
let mut x = None;
{
let y: &mut u32 = x.get_or_insert(5);
assert_eq!(y, &5);
*y = 7;
}
assert_eq!(x, Some(7));
// 从 self 中获取 Some 值, 将 self 设为 None
pub fn take(&mut self) -> Option<T>
let mut x = Some(2);
let y = x.take();
assert_eq!(x, None);
assert_eq!(y, Some(2));
let mut x: Option<u32> = None;
let y = x.take();
assert_eq!(x, None);
assert_eq!(y, None);
// predicate 返回 true 时 take Some 的值, 将 self 设置为 None
pub fn take_if<P>(&mut self, predicate: P) -> Option<T> where P: FnOnce(&mut T) -> bool
// 用 value 替换 self 值, 返回 self 以前的值
pub fn replace(&mut self, value: T) -> Option<T>
let mut x = Some(2);
let old = x.replace(5);
assert_eq!(x, Some(5));
assert_eq!(old, Some(2));
let mut x = None;
let old = x.replace(3);
assert_eq!(x, Some(3));
assert_eq!(old, None);
// 如果 self 是 Some(s) 且 other 也是 Some(o), 则返回 Some((s, o)), 否则返回 None
pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R> where F: FnOnce(T, U) -> R
let x = Some(1);
let y = Some("hi");
let z = None::<u8>;
assert_eq!(x.zip(y), Some((1, "hi")));
assert_eq!(x.zip(z), None);
// 从 Option<&T> 生成 Option<T>
impl<T> Option<&T>
pub fn copied(self) -> Option<T> where T: Copy
pub fn cloned(self) -> Option<T> where T: Clone
2 Result #
Result<T, E>
是泛型 Enum 类型。
如果一个表达式返回 Result, 则忽略返回值时编译器会警告, 可以赋值给 let _ = xxx
来消除警告。
Rust 2018 版本开始, main 函数支持返回 Result, 当结果是 Err 时会打印错误消息, 程序退出:
fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
Result 别名:
use std::fmt;
type Result<T> = std::result::Result<T, DoubleError>;
#[derive(Debug, Clone)]
struct DoubleError;
impl fmt::Display for DoubleError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "invalid first item to double")
}
}
fn double_first(vec: Vec<&str>) -> Result<i32> {
vec.first() // 返回 Option
.ok_or(DoubleError) // 将 Option 转换为 Result,Option 为 None 时对应 Result 的 Err
.and_then(|s| {
s.parse::<i32>() // 返回 Result
.map_err(|_| DoubleError) // Result::Err 时转换为另一个错误类型
.map(|i| 2 * i) // Result::Ok 时做 map 处理
})
}
// 使用自定义 Result 类型
fn print(result: Result<i32>) {
match result {
Ok(n) => println!("The first doubled is {}", n),
Err(e) => println!("Error: {}", e), // 自定义的错误类型 DourbleError 实现了 Display
}
}
Result 方法:
impl<T, E> Result<T, E>
// is_ok()/is_err() 判断 Result 的类型,但不消耗 Result
pub const fn is_ok(&self) -> bool
pub const fn is_err(&self) -> bool
pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool
pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool
// 返回一个 Option,对于 ok() 忽略了 Err 值,对于 err() 忽略了 Ok 值;
//
// 可以用于迭代器的 filter_map()/flat_map() 方法中,这些方法使用返回 Option 的泛型函数
pub fn ok(self) -> Option<T>
pub fn err(self) -> Option<E>
// 返回 Result 的引用,不消耗 Result
pub const fn as_ref(&self) -> Result<&T, &E>
pub fn as_mut(&mut self) -> Result<&mut T, &mut E>
// 对 Ok(T) 值进行转换,返回 Result<U, E>
pub fn map<U, F>(self, op: F) -> Result<U, E> where F: FnOnce(T) -> U
// 返回 U
pub fn map_or<U, F>(self, default: U, f: F) -> U where F: FnOnce(T) -> U
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U where D: FnOnce(E) -> U, F: FnOnce(T) -> U
// 将 Result 的 Err 映射为另一个错误类型 F
pub fn map_err<F, O>(self, op: O) -> Result<T, F> where O: FnOnce(E) -> F
// inspect() 会消耗 Result
pub fn inspect<F>(self, f: F) -> Result<T, E> where F: FnOnce(&T)
pub fn inspect_err<F>(self, f: F) -> Result<T, E> where F: FnOnce(&E)
pub fn as_deref(&self) -> Result<&<T as Deref>::Target, &E> where T: Deref
pub fn as_deref_mut(&mut self) -> Result<&mut <T as Deref>::Target, &mut E> where T: DerefMut
// Result 支持迭代
pub fn iter(&self) -> Iter<'_, T>
pub fn iter_mut(&mut self) -> IterMut<'_, T>
// 返回 T
pub fn expect(self, msg: &str) -> T where E: Debug
pub fn unwrap(self) -> T where E: Debug
pub fn unwrap_or(self, default: T) -> T
pub fn unwrap_or_default(self) -> T where T: Default
pub fn unwrap_or_else<F>(self, op: F) -> T where F: FnOnce(E) -> T
// Result 必须是 Err,返回 Err,如果是 Ok 则 panic
pub fn expect_err(self, msg: &str) -> E where T: Debug
pub fn unwrap_err(self) -> E where T: Debug
// Result 必须是 Ok,返回 Ok 值,但如果是 Err 则 panic
pub fn into_ok(self) -> T where E: Into<!>
pub fn into_err(self) -> E where T: Into<!>
pub fn and<U>(self, res: Result<U, E>) -> Result<U, E>
pub fn or<F>(self, res: Result<T, F>) -> Result<T, F>
pub fn and_then<U, F>(self, op: F) -> Result<U, E> where F: FnOnce(T) -> Result<U, E>
pub fn or_else<F, O>(self, op: O) -> Result<T, F> where O: FnOnce(E) -> Result<T, F>
pub unsafe fn unwrap_unchecked(self) -> T
pub unsafe fn unwrap_err_unchecked(self) -> E
3 Error #
Rust 标准库提供了 std::error::Error trait。标准库中绝大部分错误类型,如 std::io::Error, std::fmt::Error 等都实现了该 trait,故可以使用 &dyn std::error::Error 来统一保存这些错误类型。
标准库为 std::error::Error 实现了到 Box<dyn Error + ‘a> 和 Box<dyn Error + Sync + Send + ‘a> 的From trait 转换实现,所以实现了 std::error:Error trait 的错误类型都可以使用 ? 转换到 Box<dyn Error + ‘a> 和 Box<dyn Error + Sync + Send + ‘a> 类型:
impl<'a, E> From<E> for Box<dyn Error + 'a> where E: Error + 'a,
impl<'a, E> From<E> for Box<dyn Error + Sync + Send + 'a> where E: Error + Send + Sync + 'a,
最佳实践:函数返回的 Error 类型使用 Box<std::error::Error + Send + Sync + 'static>
:
- 加 Send + Sync + ‘static 后可以让 trait object 来跨线程返回, 例如在 aysnc spawn 场景中;
标准库为实现 std::error::Error trait 的类型实现了 ToString/Display/Debug trait
, 可以用 println!()
直接打印它们:
println!("error querying the weather: {}", err);
println!("error querying the weather: {:?}", err);
use std::error;
use std::fmt;
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;
// 自定义 error 类型
#[derive(Debug, Clone)]
struct EmptyVec;
// 为 error 类型实现 Display trait
impl fmt::Display for EmptyVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "invalid first item to double")
}
}
// 为自定义 error 类型实现 Error trait,std::error::Error 是 marker trait
impl error::Error for EmptyVec {}
// 返回自定义 Result 类型
fn double_first(vec: Vec<&str>) -> Result<i32> {
vec.first() // 返回 Option
.ok_or_else(|| EmptyVec.into()) // 转换为 Result,如果是 None 则返回 EmptyVec,所以结果一定是 Ok
.and_then(|s| { // 对 Ok 执行闭包,返回闭包结果
s.parse::<i32>() // 返回 Result
.map_err(|e| e.into()) // 将 Err 转换为 Box<dyn error::Error> 类型
.map(|i| 2 * i) // 对 Ok 进行转换处理
})
}
fn double_first_v2(vec: Vec<&str>) -> Result<i32> {
let first = vec.first() // 返回 Option
.ok_or(EmptyVec)?; // 将 Option 转换为 Result,为 None 时设置 Err 为 EmptyVec
let parsed = first.parse::<i32>()?;
Ok(2 * parsed)
}
自定义 Error 类型:提供更丰富/个性化的上下文和出错信息:
- 实现 fmt::Display 的 fmt() 方法;
- 实现 std::error::Error trait( Error trait 都有默认实现,一般只需标记实现);
- 实现 From<XX> trait, 将其它类型错误 XX 转换为自定义类型错误,一般用在 ? 操作符中。如果转换不一定成功,可以使用TryFrom<XX> trait, 它返回一个 Result 来指示是否转换成功;
use std::error;
use std::error::Error;
use std::num::ParseIntError;
use std::fmt;
type Result<T> = std::result::Result<T, DoubleError>;
// 自定义错误类型
#[derive(Debug)]
enum DoubleError {
EmptyVec,
Parse(ParseIntError), // 封装了其它错误类型对象
}
// 实现 Display
impl fmt::Display for DoubleError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
DoubleError::EmptyVec => write!(f, "please use a vector with at least one element"),
DoubleError::Parse(..) => write!(f, "the provided string could not be parsed as int"),
}
}
}
// 实现 Error,这里定义 source() 方法,用来返回更深层的错误对象(该对象类型必须已实现
// Error trait)
impl error::Error for DoubleError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
DoubleError::EmptyVec => None,
DoubleError::Parse(ref e) => Some(e),
}
}
}
// 实现 From trait,将其它类型对象转换为自定义类型错误,后续 ? 运算符需要
impl From<ParseIntError> for DoubleError {
fn from(err: ParseIntError) -> DoubleError {
DoubleError::Parse(err)
}
}
fn double_first(vec: Vec<&str>) -> Result<i32> {
let first = vec.first() // 返回 Option
.ok_or(DoubleError::EmptyVec)?; // 转为 Result,参数指定为 None 时对应的 Err 值
let parsed = first.parse::<i32>()?; // 自动使用 From trait 转换错误类型
Ok(2 * parsed)
}
fn print(result: Result<i32>) {
match result {
Ok(n) => println!("The first doubled is {}", n),
Err(e) => {
println!("Error: {}", e);
// 提取出更深层次的错误,如果未自定义 source() 方法,则返回 None
if let Some(source) = e.source() {
println!(" Caused by: {}", source);
}
},
}
}
第三方 thiserror crate
为自定义 Error 类型提供了基于 derive macro 的快捷实现,可以避免上面的样板式代码:
// https://github.com/Abraxas-365/langchain-rust/blob/main/src/agent/error.rs
use thiserror::Error;
use crate::{chain::ChainError, language_models::LLMError, prompt::PromptError};
#[derive(Error, Debug)]
pub enum AgentError {
#[error("LLM error: {0}")]
LLMError(#[from] LLMError),
#[error("Chain error: {0}")]
ChainError(#[from] ChainError),
#[error("Prompt error: {0}")]
PromptError(#[from] PromptError),
#[error("Tool error: {0}")]
ToolError(String),
#[error("Missing Object On Builder: {0}")]
MissingObject(String),
#[error("Missing input variable: {0}")]
MissingInputVariable(String),
#[error("Serde json error: {0}")]
SerdeJsonError(#[from] serde_json::Error),
#[error("Error: {0}")]
OtherError(String),
}