当前位置: 首页 > news >正文

rust学习笔记17-异常处理

今天聊聊rust中异常错误处理

1. 基础类型:Result 和 Option,之前判断空指针就用到过

Option<T>
  • 用途:表示值可能存在(Some(T))或不存在(None),适用于无需错误信息的场景。

    fn 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 为错误类型。

    fn 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,但可附加错误信息。

let content = read_file("file.txt").unwrap(); // 危险:可能崩溃

let content = read_file("file.txt").expect("读取文件失败");

3.错误传播:? 运算符
        简化错误传播:自动将错误返回给调用者,需函数返回 Result。

fn process_file() -> Result<(), std::io::Error> {
    let content = read_file("file.txt")?; // 错误时直接返回
    println!("Content: {}", content);
    Ok(())
}

4.自定义错误,一般接口校验用的多

写一个校验错误有如下四个,id为空,name重名,id查询为空,name限制30字符超长错误

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"

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在开发调试过程中用比较多,自定义错误,校验类函数用的多。

相关文章:

  • 《心理学与生活》2025最新网课答案
  • Python的Pytest(2)
  • C语言 常用系统函数
  • 蓝桥云客 找素数
  • reconstruct_3d_object_model_for_matching例子
  • C# WPF编程-Menu
  • 戴尔系列电脑安装UBUNTU系统
  • MySQL事务:确保数据一致性的关键机制
  • fastapi+angular宠物领养系统
  • 基于Nvidia Jetson Nano边缘计算设备使用TensorRT部署YOLOv8模型实现目标检测推理
  • 基于Python+Ollama DeepSeek与MySQL进行数据分析探索
  • apache-maven-3.9.9 详细安装配置教程(2025版)
  • 贪心算法作业参考:P1106,P4995,P5019
  • 2000-2019年各省地方财政税收收入数据
  • 深入剖析React中setState的执行机制与实现原理
  • LeetCode算法题(Go语言实现)_04
  • 深入解析 GORM 的 Model 方法:隐式选择与模型绑定的艺术
  • 【安全运营】用户与实体行为分析(UEBA)浅析
  • 【从零开始学习计算机科学与技术】计算机网络(七)应用层
  • ClickHouse Docker 容器迁移指南:从测试环境到离线正式环境
  • 浙江美术馆馆长人民日报撰文:打开更辽阔的审美场域
  • 大环线呼之欲出,“金三角”跑起来了
  • 上海虹桥国际咖啡文化节开幕,推出茶咖文化特色街区、宝妈咖啡师培训
  • 昆明公布3起经济犯罪案例:一人持有820余万假美元被判刑十年
  • 坚持吃素,是不是就不会得高血脂了?
  • 菲律宾中期选举初步结果出炉,杜特尔特家族多人赢得地方选举