Rust anyhow 简明教程

ops/2024/9/20 7:26:03/ 标签: rust, 开发语言, 后端

anyhow 是 Rust 中的一个库,旨在提供灵活的、具体的错误处理能力,建立在 std::error::Error 基础上。它主要用于那些需要简单错误处理的应用程序和原型开发中,尤其是在错误类型不需要被严格区分的场景下。

以下是 anyhow 的几个关键特性:

  • 易用性: anyhow 提供了一个 Error 类型,这个类型可以包含任何实现了 std::error::Error 的错误。这意味着你可以使用 anyhow::Error 来包装几乎所有类型的错误,无需担心具体的错误类型。
  • 简洁的错误链: anyhow 支持通过 ? 操作符来传播错误,同时保留错误发生的上下文。这让错误处理更加直观,同时还能保留错误链,便于调试。
  • 便于调试: anyhow 支持通过 {:#} 格式化指示符来打印错误及其所有相关的上下文和原因,这使得调试复杂的错误链变得更加简单。
  • 无需关心错误类型: 在很多情况下,特别是在应用程序的顶层,你可能不需要关心错误的具体类型,只需要知道出错了并且能够将错误信息传递给用户或日志。anyhow 让这一过程变得简单,因为它可以包装任何错误,而不需要显式地指定错误类型。

使用 anyhow 的典型场景包括快速原型开发、应用程序顶层的错误处理,或者在库中作为返回错误类型的一个简便选择,尤其是在库的使用者不需要关心具体错误类型的时候。

anyhow::Error

anyhow::Erroranyhow 库定义的一个错误类型。它是一个包装器(wrapper)类型,可以包含任何实现了 std::error::Error trait 的错误类型。这意味着你可以将几乎所有的错误转换为 anyhow::Error 类型,从而在函数之间传递,而不需要在意具体的错误类型。这在快速原型开发或应用程序顶层错误处理中特别有用,因为它简化了错误处理的逻辑。

它的定义如下:

rust">#[cfg_attr(not(doc), repr(transparent))]
pub struct Error {inner: Own<ErrorImpl>,
}

其中核心是 ErrorImpl

rust">#[repr(C)]
pub(crate) struct ErrorImpl<E = ()> {vtable: &'static ErrorVTable,backtrace: Option<Backtrace>,// NOTE: Don't use directly. Use only through vtable. Erased type may have// different alignment._object: E,
}

ErrorImpl 是一个内部结构体,用于实现 anyhow::Error 类型的具体功能。它包含了三个主要字段:

  • vtable 是一个指向静态虚拟表的指针,用于动态派发错误相关的方法。
  • backtrace 是一个可选的回溯(Backtrace)类型,用于存储错误发生时的调用栈信息。
  • _object 字段用于存储具体的错误对象,其类型在编译时被擦除以提供类型安全的动态错误处理。

这种设计允许 anyhow 错误封装并表示各种不同的错误类型,同时提供了方法动态派发和回溯功能,以便于错误调试。

anyhow::Error 可以包含任何实现了 std::error::Error trait 的错误类型,这里因为下面的 impl

impl<E> StdError for ErrorImpl<E>
whereE: StdError,
{fn source(&self) -> Option<&(dyn StdError + 'static)> {unsafe { ErrorImpl::error(self.erase()).source() }}#[cfg(error_generic_member_access)]fn provide<'a>(&'a self, request: &mut Request<'a>) {unsafe { ErrorImpl::provide(self.erase(), request) }}
}

anyhow::Result

anyhow::Result 是一个别名(type alias),它是 std::result::Result<T, anyhow::Error> 的简写。在使用 anyhow 库进行错误处理时,你会频繁地看到这个类型。它基本上是标准的 Result 类型,但错误类型被固定为 anyhow::Error。这使得你可以很容易地在函数之间传递错误,而不需要声明具体的错误类型。

rust">pub type Result<T, E = Error> = core::result::Result<T, E>;

使用 anyhow::Result 的好处在于它提供了一种统一的方式来处理错误。你可以使用 ? 操作符来传播错误,同时保留错误的上下文信息和回溯。这极大地简化了错误处理代码,尤其是在多个可能产生不同错误类型的操作链中。

3 个核心使用技巧

  • 使用 Result<T, anyhow::Error> 或者 anyhow::Result<T> 作为返回值,然后利用 ? 语法糖无脑传播报错。
  • 使用 with_context(f) 来附加错误信息。
  • 使用 downcast 反解具体的错误类型。

实战案例

下面我们用一个案例来体会 anyhow 的使用方式:

我们的需求是:打开一个文件,解析文件中的数据并进行大写化,然后输出处理后的数据。

rust">use anyhow::{Result, Context};
use std::{fs, io};// 1. 读取文件、解析数据和执行数据操作都可能出现错误,
// 所以我们需要返回 Result 来兼容异常情况。
// 这里我们使用 anyhow::Result 来简化和传播错误。
fn read_and_process_file(file_path: &str) -> Result<()> {// 尝试读取文件let data = fs::read_to_string(file_path)// 2. 使用 with_context 来附加错误信息,然后利用 ? 语法糖传播错误。.with_context(||format!("failed to read file `{}`", file_path))?;// 解析数据let processed_data = parse_data(&data).with_context(||format!("failed to parse data from file `{}`", file_path))?;// 执行数据操作perform_some_operation(processed_data).with_context(|| "failed to perform operation based on file data")?;Ok(())
}fn parse_data(data: &str) -> Result<String> {Ok(data.to_uppercase())
}fn perform_some_operation(data: String) -> Result<()> {println!("processed data: {}", data);Ok(())
}fn main() {let file_path = "./anyhow.txt";// 执行处理逻辑let res =  read_and_process_file(file_path);// 处理结果match res {Ok(_) => println!("successfully!"),Err(e) => {// 3. 使用 downcast 来反解出实际的错误实例,本案例中可能出现的异常是 io::Error。if let Some(my_error) = e.downcast_ref::<io::Error>() {println!("has io error: {:#}", my_error);} else {println!("unknown error: {:?}", e);}}}
}

http://www.ppmy.cn/ops/48562.html

相关文章

陕西移动联合中兴通讯,赋能5G RedCap智慧工厂建设

前不久&#xff0c;陕西移动联合中兴通讯、高新兴等产业伙伴在中兴通讯西安智能终端生产基地顺利完成5G RedCap在智慧工厂的应用实践。本次实践证明了5G RedCap在智慧工厂场景下的应用可行性&#xff0c;为RedCap在工业智能制造行业的应用打下基础。   5G RedCap技术是5G-A实现…

Ubuntu软件操作的相关命令

更新源 : sudo apt-get update 安装包 : sudo apt-get install package 删除包 : sudo apt-get remove package 搜索软件包 : sudo apt-cache search package 获取包的相关信息&#xff0c;如说明、⼤⼩、版本等 : sudo apt-cache show package 重新安装包 : sudo apt-get…

机器视觉:光源的类型以及主要参数

光源在机器视觉中起着决定性的作用&#xff0c;决定了视觉算法的复杂性&#xff0c;也决定了视觉系统的精度和稳定性。光源用于突出目标物体的特征&#xff0c;增加目标物体与背景的对比度&#xff0c;克服环境光线的干扰。光源的选择与打光方式在视觉系统的前期评估中非常重要…

spring和Mybatis的各种查询

文章目录 六**、MyBatis的各种查询功能**6.1、查询一个实体类的对象6.2、查询一个list集合6.3、查询单个数据6.4、查询一条数据为Map集合6.5、查询多条数据为Map集合 七、**特殊SQL的执行**7.1、模糊查询7.2、批量删除7.3、动态设置表名7.4、添加功能获取自增的主键 八、**自定…

攻防演练之-成功的钓鱼邮件溯源

书接上文&#xff0c;《网络安全攻防演练风云》专栏之攻防演练之-网络安全产品大巡礼二&#xff0c;这里。 演练第一天并没有太大的波澜&#xff0c;白天的时间过得很快。夜色降临&#xff0c;攻防演练中心内的灯光依旧明亮。对于网络安全团队来说&#xff0c;夜晚和白天并没有…

如何把路由器设备的LAN口地址为三大私网地址

要将路由器的LAN口地址配置为三大私有IP地址范围之一&#xff08;10.0.0.0/8、172.16.0.0/12 或 192.168.0.0/16&#xff09;&#xff0c;我们需要访问路由器的管理界面并进行相应的设置。 下面是步骤&#xff1a; 连接到路由器&#xff1a; 连接到路由器的管理界面&#xf…

Flutter基础 -- Flutter容器布局

目录 1. MaterialApp 1.1 组件定义 1.2 主要功能和属性 1.3 示例 2. 脚手架 Scaffold 2.1 定义 2.2 Scaffold 的属性 2.3 示例 PS: 对于 Scaffold 和 MaterialApp 3. 线性布局 Column Row 3.1 Row 3.2 Column 4. 盒模型 Box Model 4.1 定义 4.2 示例 5. 容器 C…

C#——类和对象详情

类和对象 类 类是一种数据结构&#xff0c;它可以包含数据成员&#xff08;常量和字段&#xff09;、函数成员&#xff08;方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数&#xff09;以及嵌套类型。类类型支持继承&#xff0c;继承是一种机制&…

深入讲解Java线程中 wait 和 notify 的用法和原理

基本概念 wait 和 notify 是 Java 中用于线程间通信的方法&#xff0c;定义在 Object 类中。它们的主要作用是在多线程环境中协调线程的执行顺序。 wait 方法 作用&#xff1a;使当前线程进入等待状态&#xff0c;直到其他线程调用 notify 或 notifyAll 方法唤醒它。调用条件…

【车载音视频电脑】嵌入式AI分析车载DVR,支持8路1080P

产品特点 采用H.265 & H.264编解码&#xff0c;节约存储空间、传输流量&#xff1b; 高分辨率&#xff1a;支持8路1080P*15FPS/4路1080P*30FPS、720P、D1等编解码&#xff1b; 支持1张SATA硬盘&#xff0c;取用方便&#xff0c;满足大容量存储要求&#xff1b; 支持1个…

[word] word表格如何设置外框线和内框线 #媒体#笔记

word表格如何设置外框线和内框线 点击表格的左上角按钮从而选中表格 点击边框按钮边上的下拉箭头&#xff0c;选择边框和底纹 点击颜色边上的下拉箭头&#xff0c;选择红色 点击取消掉中间的边框&#xff0c;只保留外围边框 点击颜色边上的下拉箭头&#xff0c;选择另外一个颜…

common.js和es6中模块引入的区别

common.js CommonJS 是一种模块系统&#xff0c;主要用于 Node.js 环境。它使用 require 函数来引入模块&#xff0c;并使用 module.exports 来导出模块。 语法&#xff1a; 导出模块&#xff1a; // moduleA.js const name Jo; module.exports name;// 或者导出一个对象…

openlayers 绘图功能,编辑多边形,长度面积测量,tip提示(七)

本篇介绍一下使用openlayers添加tips&#xff0c;比如测量时&#xff0c;实时显示长度、面积等&#xff0c;两种方法&#xff1a; 使用Overlay&#xff0c;会添加指定的HTML元素到dom中&#xff0c;会跟随地图的平移】缩放等动作使用vector样式&#xff0c;会渲染到地图的canv…

【十大排序算法】归并排序

归并排序&#xff0c;如同秋日落叶&#xff0c;分散而细碎&#xff0c; 然而风吹叶动&#xff0c;自然而有序&#xff0c; 彼此相遇&#xff0c;轻轻合拢&#xff0c; 最终成就&#xff0c;秩序之谧。 文章目录 一、归并排序二、发展历史三、处理流程四、算法实现五、算法特性…

使用C#快速搭建一个在windows运行的exe应用

文章目录 一、前言1.1 编写语言需要工具1.2 选择自己需要的组件进行安装 二、新建项目1.1 新建一个 .NET4.x 的项目1.2 添加一个小案例1.3 对界面进行美化1.3.1、配置Form属性1.3.2、配置Button按钮 1.4 查看组将的相关代码 三、后记 一、前言 这是一个比较旧的内容&#xff0…

Redis宣布商用后,Redis国产化替代方案有那些?

一、背景 Redis作为使用最为广泛的开源缓存中间件&#xff0c;现已成为IT开发中必不可少的核心组件。官方修改协议印证了“开源”不意味着“无偿使用”&#xff0c;相关限制或将对基于开源Redis提供中间件产品的厂商&#xff0c;及提供Redis服务的云厂商产生一定影响。 二、国…

java版B/S架构UWB人员定位系统源码spring boot+vue技术架构uwb定位装置-工业级UWB室内定位系统源码

java版B/S架构UWB人员定位系统源码spring bootvue技术架构uwb定位装置-工业级UWB室内定位系统源码 本套系统运用UWB定位技术&#xff0c;开发的高精度人员定位系统&#xff0c;通过独特的射频处理&#xff0c;配合先进的位置算法&#xff0c;可以有效计算复杂环境下的人员与物…

【html】如何利用HTML+CSS制作自己的印章

大家有没有尝试过用HTML和CSS制作自己的印章. 首先印章具有两个最基本的特点就是它是圆形的并且有边框 当然它还有一些其他的属性吗&#xff0c;废话不多说我们直接上源码&#xff1a; 效果图&#xff1a; 源码&#xff1a; html&#xff1a; <!DOCTYPE html> <h…

2024 Java 异常—面试常见问题

目录 一、异常的分类 二、throw和throws都是异常处理的关键字&#xff0c;二者区别。 三、try-catch-finally 中&#xff0c;如果 catch 中 return 了&#xff0c;finally 还会执行吗&#xff1f; 四、try-catch-finally 中哪个部分可以省略&#xff1f; 五、常见的 Runti…

C++:SLT容器-->deque

C:SLT容器-->deque 1. 构造函数2. deque 赋值操作3. deque 大小操作4. deque 插入和删除5. deque 容器数据存取6. deque 排序操作 双端数组&#xff0c;可以对头部和尾部进行插入删除操作 需要导入头文件#include <deque> 1. 构造函数 deque deqT; // 默认构造函数 de…