Rust anyhow 简明教程

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 类型,从而在函数之间传递,而不需要在意具体的错误类型。这在快速原型开发或应用程序顶层错误处理中特别有用,因为它简化了错误处理的逻辑。

它的定义如下:

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

其中核心是 ErrorImpl

#[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。这使得你可以很容易地在函数之间传递错误,而不需要声明具体的错误类型。

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 的使用方式:

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

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.mzph.cn/pingmian/25564.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MAVEN架构项目管理工具

1、什么是maven Maven是跨平台的项目管理工具。主要服务于基于Java平台的项目构建&#xff0c;依赖管理和项目信息管理。 2、maven的目标&#xff1a;Maven的主要目标是为了使开发人员在最短的时间内领会项目的所有状态 3、使用maven不需要考虑各个依赖的版本&#xff0c;因…

Follow Carl To Grow|【LeetCode】530.二叉搜索树的最小绝对差,501.二叉搜索树中的众数,236. 二叉树的最近公共祖先

【LeetCode】530.二叉搜索树的最小绝对差 题意&#xff1a;给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 思路&#xff1a;中序遍历拿到递增序列&#xff0c;然后求相邻…

【将xml文件转yolov5训练数据txt标签文件】连classes.txt都可以生成

将xml文件转yolov5训练数据txt标签文件 前言一、代码解析 二、使用方法总结 前言 找遍全网&#xff0c;我觉得写得最详细的就是这个博文⇨将xml文件转yolov5训练数据txt标签文件 虽然我还是没有跑成功。那个正则表达式我不会改QWQ&#xff0c;但是不妨碍我会训练ai。 最终成功…

UE5中在地形中加入湖、河

系统水资产添加 前提步骤123 完成 前提 使用版本 UE5.0.3,使用插件为UE内置的Water和water Extras. 步骤 1 记得重启 2 增加地形&#xff0c;把<启用编辑图层>勾选 如果地形没有勾选上编辑图层&#xff0c;那么就会导致湖、河等水景象无法融入地形。 如果忘记勾选…

Hive知识体系保姆级教程

一. Hive概览 1.1 hive的简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供类SQL查询功能。 其本质是将SQL转换为MapReduce/Spark的任务进行运算&#xff0c;底层由HDFS来提供数据的存储&#xff0c;说白了h…

如何从 Android 图库中恢复误删除的照片

如果您正在阅读这篇文章&#xff0c;那么您肯定意外地从 Android 设备中删除了照片。并且您正在寻找一种简单的方法来恢复 Android 图库中已删除的照片。 从图库恢复已删除的照片 随着技术的进步&#xff0c;现在使用单个设备&#xff08;即 Android 手机&#xff09;&#xf…

【Python】 了解二分类:机器学习中的基础任务

我已经从你的 全世界路过 像一颗流星 划过命运 的天空 很多话忍住了 不能说出口 珍藏在 我的心中 只留下一些回忆 &#x1f3b5; 牛奶咖啡《从你的全世界路过》 在机器学习和数据科学领域&#xff0c;分类问题是最常见的任务之一。分类问题可以分为多类分…

使用贝塞尔曲线实现一个iOS时间轴

UI效果 实现的思路 就是通过贝塞尔曲线画出时间轴的圆环的路径&#xff0c;然后 使用CAShaper来渲染UI&#xff0c;再通过 animation.beginTime [cilrclLayer convertTime:CACurrentMediaTime() fromLayer:nil] circleTimeOffset 来设置每个圆环的动画开始时间&#xff0c; …

探索ChatGPT-4在解决化学知识问题上的研究与应用

1. 概述 近年来&#xff0c;人工智能的发展主要集中在 GPT-4 等大型语言模型上。2023 年 3 月发布的这一先进模型展示了利用广泛知识应对从化学研究到日常问题解决等复杂挑战的能力。也开始进行研究&#xff0c;对化学的各个领域&#xff0c;从化学键到有机化学和物理化学&…

【设计模式】行为型设计模式之 备忘录模式(快照模式)

介绍 备忘录应用场景明确并且有限&#xff0c;一般用来数据的防丢失、撤销和恢复。对大对象的备份和恢复&#xff0c;备忘录模式能有效的节省时间和空间开销。 定义 备忘录模式&#xff1a;也称为快照模式&#xff0c;在不违背封装原则的前提下&#xff0c;捕获一个对象的内…

BFS实现图的点的层次-java

加强对广度优先搜索的理解&#xff0c;其实就是主要的3个步骤&#xff0c;外加数组模拟单链表是基础&#xff0c;要搞懂。 目录 前言 一、图中点的层次 二、算法思路 1.广度优先遍历 2.算法思路 三、代码如下 1.代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入…

探索基于订阅式的电视App:Android TV 端强大的开源视频播放器

探索基于订阅式的电视App&#xff1a;Android TV 端强大的开源视频播放器 在智能电视和流媒体日益普及的今天&#xff0c;一款强大的视频播放器是家庭娱乐的重要组成部分。正是这样一款为Android TV设计的开源视频播放器。本文将深入探讨电视盒子OSC的技术特点、使用方法以及其…

在Java中类中的成员变量和成员方法在jvm中如何协调调用及优化

第一部分&#xff1a; 在Java中类中的成员变量和成员方法在jvm中如何协调调用 在Java中&#xff0c;类的成员变量和成员方法在JVM&#xff08;Java虚拟机&#xff09;中的表现方式有一定的规则和结构。以下是对成员变量和成员方法在JVM中的一些关键点的解释&#xff1a; 成员…

抛弃昂贵BI,企业仍可低成本实现数据分析

有的读者看完《BI工具选型不入坑&#xff0c;你要这么选》这篇文章就陷入迷茫了&#xff0c;我要做企业级数据分析&#xff0c;看过去各家产品都各有千秋&#xff0c;实在难以抉择&#xff0c;或者已经选了仍是纠结不已。 这里我抛出另一种思路&#xff1a;如果不用BI&#xf…

Terminal Multiplexer的使用

tmux&#xff08;Terminal Multiplexer&#xff0c;终端复用器&#xff09;是一个可以在单个终端窗口中运行多个独立会话的软件工具。它允许用户在同一个终端窗口内分割屏幕&#xff0c;创建多个虚拟终端&#xff0c;这样就可以同时监视和控制多个进程&#xff0c;即使终端窗口…

C#操作MySQL从入门到精通(17)——使用联结

前言: 我们在查询数据的过程中有时候查询的数据不是来自一个表而是来自多个表,本文使用的测试数据如下: 本文使用了两个表student_info、address_info student_info的数据如下: address_info的数据如下: 1、内联结 所谓内联结就是求交集,两个表都有的数据才是有效数…

94、二叉树的迭代遍历

实现对二叉树的前后序非递归遍历 题解&#xff1a; 递归的实现就是&#xff1a;递去&#xff0c;归来。每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中&#xff0c;然后递归返回的时候&#xff0c;从栈顶弹出上一次递归的各项参数&#xff0c;所以这就是…

46.django - 多语言配置

1.Django 多语言基础知识 多语言站点可以让不同语言的用户更好地使用和理解网站内容&#xff0c;提升用户体验和覆盖范围。为了实现多语言功能&#xff0c;我们将使用Django内置的国际化和本地化支持。我收集了一些知识点整理在这一部分&#xff0c;感兴趣的可以看看。直接跳过…

安装搭建java版的悟空crm遇到 网络错误请稍候再试 终极解决办法(hrm人力资源模块)

java版 项目目录 ├── build – webpack 配置文件 ├── config – 项目配置文件 ├── src – 源码目录 │ ├── api – axios请求接口 │ ├── assets – 静态图片资源文件 │ ├── components – 通用组件 │ ├── directives – 通用指令 │ ├── filters –…

项目中的任务调度和消息队列方案详解

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 任务…