今天聊聊rust中异常错误处理
- 基础类型:Result 和 Option,之前判断空指针就用到过
Option<T>
-
用途 :表示值可能存在(
Some(T)
)或不存在(None
),适用于无需错误信息的场景。rustfn print_list(head: Option<&Box<ListNode>>) { match head { Some(node) => { let mut current = Some(node); // 初始化当前节点指针 while let Some(node) = current { print!("{} -> ", node.val); current = node.next.as_ref(); // 使用 as_ref() 获取对 next 的引用 } println!("None"); } None => { println!("链表为空"); } } }
Result<T, E>
-
用途 :表示操作可能成功(
Ok(T)
)或失败(Err(E)
),E
为错误类型。rustfn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err(String::from("Denominator cannot be zero!")) } else { Ok(numerator / denominator) } }
2.快捷方法:unwrap 和 expect
unwrap():成功返回值,失败则 panic。
expect(msg):类似 unwrap,但可附加错误信息。
rust
let content = read_file("file.txt").unwrap(); // 危险:可能崩溃
let content = read_file("file.txt").expect("读取文件失败");
3.错误传播:? 运算符
简化错误传播:自动将错误返回给调用者,需函数返回 Result。
rust
fn process_file() -> Result<(), std::io::Error> {
let content = read_file("file.txt")?; // 错误时直接返回
println!("Content: {}", content);
Ok(())
}
4.自定义错误,一般接口校验用的多
写一个校验错误有如下四个,id为空,name重名,id查询为空,name限制30字符超长错误
rust
use std::fmt;
//原生写法
// 定义校验错误枚举
#[derive(Debug, PartialEq)]
pub enum ValidationError {
IdEmpty,
NameDuplicate(String), // 携带重复的名称
IdNotFound(String), // 携带未找到的ID
NameTooLong(usize), // 携带实际长度
}
// 实现错误描述
impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ValidationError::IdEmpty => write!(f, "ID不能为空"),
ValidationError::NameDuplicate(name) =>
write!(f, "名称 '{}' 已存在", name),
ValidationError::IdNotFound(id) =>
write!(f, "ID '{}' 不存在", id),
ValidationError::NameTooLong(len) =>
write!(f, "名称长度不能超过30字符(当前长度:{})", len),
}
}
}
// 实现标准错误Trait
impl std::error::Error for ValidationError {}
使用 thiserror 简化(推荐)
dependencies
thiserror = "1.0"
rust
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum ValidationError {
#[error("ID不能为空")]
IdEmpty,
#[error("名称 '{0}' 已存在")]
NameDuplicate(String),
#[error("ID '{0}' 不存在")]
IdNotFound(String),
#[error("名称长度不能超过30字符(当前长度:{0})")]
NameTooLong(usize),
}
// 校验用户输入
pub fn validate_user_input(id: &str, name: &str) -> Result<(), ValidationError> {
// 检查ID是否为空
if id.trim().is_empty() {
return Err(ValidationError::IdEmpty);
}
// 检查名称长度
if name.len() > 30 {
return Err(ValidationError::NameTooLong(name.len()));
}
Ok(())
}
// 模拟检查名称是否重复
pub fn check_name_unique(name: &str) -> Result<(), ValidationError> {
let existing_names = vec!["Alice", "Bob"];
if existing_names.contains(&name) {
return Err(ValidationError::NameDuplicate(name.to_string()));
}
Ok(())
}
// 模拟根据ID查询数据是否存在
pub fn find_by_id(id: &str) -> Result<(), ValidationError> {
let valid_ids = vec!["1001", "1002"];
if !valid_ids.contains(&id) {
return Err(ValidationError::IdNotFound(id.to_string()));
}
Ok(())
}
fn main() {
let existing_names = vec![String::from("Alice"), String::from("Bob")];
// 测试不同的错误场景
match validate_user_input("", "Charlie") {
Ok(_) => println!("校验成功."),
Err(e) => println!("校验失败: {}", e),
}
match check_name_unique( "Alice") {
Ok(_) => println!("校验成功."),
Err(e) => println!("校验失败: {}", e),
}
match find_by_id("789") {
Ok(_) => println!("校验成功."),
Err(e) => println!("校验失败: {}", e),
}
match validate_user_input("123", &"A".repeat(31)) {
Ok(_) => println!("校验成功."),
Err(e) => println!("校验失败: {}", e),
}
}

总结,rust没有try/catch这样的异常处理机制,而是通过Result 和 Option这样枚举处理,unwrap 和 expect在开发调试过程中用比较多,自定义错误,校验类函数用的多。