Rust 实战thiserror+自定义错误消息体

news/2024/5/19 6:45:20

导航

  • 一、背景
  • 二、实践
    • 1、导入thiserror
    • 2、自定义错误消息体
      • (1)创建ErrMsg.rs和创建自定义结构体
      • (2)lib.rs添加ErrMsg
      • (3)main函数
      • (4)完整代码

一、背景

开发中遇到需要通用、能够满足自定义 的错误输出方式,
thiserror是一个不错的工具包,在此基础上我还想加一些自定义的错误消息体,比如HTTP类的错误信息,打印状态码和错误内容

二、实践

1、导入thiserror

thiserror = "1.0"

2、自定义错误消息体

(1)创建ErrMsg.rs和创建自定义结构体

若想能够打印错误信息,为自定义结构体实现display和Debug特征,看完整代码

use crate::Display;
use std::error::Error;
use std::fmt::Debug;
use std::fmt::{self};
// ErrMsg 是自定义错误类型,
// 为 ErrMsg 自动派生 Debug 特征
#[derive(Debug)]
pub struct ErrMsg {pub code: u32,pub msg: String,
}// 为 AppError 实现 std::fmt::Display 特征
impl fmt::Display for ErrMsg {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "ErrMsg: {{code:{},msg :{} }}", self.code, self.msg) // user-facing output}
}pub fn print_err<E>(e: E)
whereE: Display + Debug + Error,
{print!("{}", e);
}

(2)lib.rs添加ErrMsg

// src/lib.rs
pub mod ErrBean;

(3)main函数

使用thiserror 定义枚举,枚举应该包括你需要的所有Error类型

enum MyError {#[error("invalid argument: {0}")]InvalidArgument(String),#[error("io error: {0}")]IoError(#[from] std::io::Error),#[error("this is display trait  output  :{0}")]//ErrMsg的display的输出,会替换这里的{0}ErrMsg(ErrMsg),
}

完整main函数

use hello_package::ErrBean::*;
use std::fmt::{self};
use std::fs::File;
use std::io::{self, Read};
use thiserror::Error;
#[derive(Error, Debug)]
enum MyError {#[error("invalid argument: {0}")]InvalidArgument(String),#[error("io error: {0}")]IoError(#[from] std::io::Error),#[error("this is display trait  output  :{0}")]ErrMsg(ErrMsg),
}
fn read_username_from_file() -> Result<String, MyError> {// 打开文件,f是`Result<文件句柄,io::Error>`let f = File::open("hello.txt");let mut f = match f {// 打开文件成功,将file句柄赋值给fOk(file) => file,// 打开文件失败,将错误返回(向上传播)Err(e) => return Err(MyError::IoError(e)),};// 创建动态字符串slet mut s = String::new();// 从f文件句柄读取数据并写入s中match f.read_to_string(&mut s) {// 读取成功,返回Ok封装的字符串Ok(_) => Ok(s),// 将错误向上传播Err(e) => return Err(MyError::IoError(e)),}
}
fn produce_error() -> Result<String, MyError> {let err_msg = ErrMsg {code: 400,msg: String::from("自定义错误内容"),};Err(MyError::ErrMsg(err_msg))
}fn main() {let res = produce_error();//可以替换成read_username_from_fileif let Ok(e) = res {print!("{}", e);} else if let Err(e) = res {print!("{}", e);}
}

输出结果为

this is display trait  output  :ErrMsg: {code:400,msg :自定义错误内容 }%   

(4)完整代码

为了保证模块化开发,关于错误实体的定义和方法实现应该都放到一个rs文件中,别的文件需要使用时直接导入就好,所以ErrMsg.rs用来定义我们的thiserror和自定义错误消息结构体
ErrMsg.rs

use core::fmt::Display;
use std::error::Error;
use std::fmt::Debug;
use std::fmt::{self};use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyError {#[error("invalid argument: {0}")]//{0}是占位符号,原本error的打印信息会替换这个占位符InvalidArgument(String),#[error("io error: {0}")]IoError(#[from] std::io::Error),#[error("this is display trait  output  :{0}")]ErrMsg(ErrMsg),
}// ErrMsg 是自定义错误类型,它可以是当前包中定义的任何类型,在这里为了简化,我们使用了单元结构体作为例子。
// 为 ErrMsg 自动派生 Debug 特征
#[derive(Debug)]
pub struct ErrMsg {pub code: u32,pub msg: String,
}// 为 ErrMsg 实现 std::fmt::Display 特征
impl fmt::Display for ErrMsg {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "ErrMsg: {{code:{},msg :{} }}", self.code, self.msg) // user-facing output}
}pub fn print_err<E>(e: E)
whereE: Display + Debug + Error,
{print!("{}", e);
}

main.rs

use hello_package::ErrBean::*;
use std::fmt::{self};
use std::fs::File;
use std::io::{self, Read};fn read_username_from_file() -> Result<String, MyError> {// 打开文件,f是`Result<文件句柄,io::Error>`let f = File::open("hello.txt");let mut f = match f {// 打开文件成功,将file句柄赋值给fOk(file) => file,// 打开文件失败,将错误返回(向上传播)Err(e) => return Err(MyError::IoError(e)),};// 创建动态字符串slet mut s = String::new();// 从f文件句柄读取数据并写入s中match f.read_to_string(&mut s) {// 读取成功,返回Ok封装的字符串Ok(_) => Ok(s),// 将错误向上传播Err(e) => return Err(MyError::IoError(e)),}
}
fn produce_error() -> Result<String, MyError> {let err_msg = ErrMsg {code: 400,msg: String::from("自定义错误内容"),};Err(MyError::ErrMsg(err_msg))
}fn main() {let res = produce_error();if let Ok(e) = res {print!("{}", e);} else if let Err(e) = res {print!("{}", e);}
}

在这里插入图片描述


http://www.mrgr.cn/p/42887783

相关文章

Latex 编辑论文的一些坑

如何插入图片首先,要使用pdf作为图片的保存格式,这样图片可以以原始分辨率插入。但要实现高清图片,需要几个条件,请一定按照我说的步骤来1. 在ppt里编辑你想要的图片样子、排布、文字(真正标准的做法是在latex中用input写入文字)等2.将有效图片区域移动到ppt整个画布的左…

基于Springboot的旅游管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的旅游管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

【华为】路由综合实验(OSPF+BGP基础)

【华为】路由综合实验 实验需求拓扑配置AR1AR2AR3AR4AR5PC1PC2 查看通信OSPF邻居OSPF路由表 BGPBGP邻居BGP 路由表 配置文档 实验需求 ① 自行规划IP地址 ② 在区域1里面 启用OSPF ③ 在区域1和区域2 启用BGP&#xff0c;使AR4和AR3成为eBGP&#xff0c;AR4和AR5成为iBGP对等体…

ARM64_Ubuntu_Chrome_Python 镜像搭建最终版

ARM64_Ubuntu_Chrome_Python 镜像搭建最终版dockerfile FROM ubuntu:24.04 RUN apt-get update && apt-get install gnupg -y && apt-get clean RUN sh <<EOF cat > /etc/apt/sources.list <<EOS deb http://ftp.de.debian.org/debian sid mai…

[转帖]Linux内核版本升级,性能到底提升多少?

https://plantegg.github.io/2019/12/24/Linux%E5%86%85%E6%A0%B8%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%EF%BC%8C%E6%80%A7%E8%83%BD%E5%88%B0%E5%BA%95%E6%8F%90%E5%8D%87%E5%A4%9A%E5%B0%91%EF%BC%9F%E6%8B%BF%E6%95%B0%E6%8D%AE%E8%AF%B4%E8%AF%9D/ 背景 X 产品在公有云售…

初识webpack项目

新建一个空的工程 -> % mkdir webpack-project 为了方便追踪执行每一个命令&#xff0c;最终产生了哪些变更&#xff0c;将这个空工程初始化成git项目 -> % cd webpack-project/-> % git init Initialized empty Git repository in /Users/lixiang/frontworkspace/…

WPF应用程序XAML

当WPF应用程序创建好后&#xff0c;系统会自动添加一个Grid控件到窗体上&#xff0c;通过Grid控件能够方便地对界面进行布局.下面代码中为Grid控件添加了两行两列&#xff0c;分别用RowDefinitions属性ColumnDefinitions属性表示行的集合和列的集合&#xff0c;集合中有RowDefi…

Blazor/Hybird 触屏下单程序调优笔记

环境 Blazor Net8.0 + FreeSql + Bootstrap Blazor 组件 以下都是自己瞎琢磨的和官网资料搬运,肯定有不少错漏和不合理的地方,非常希望各位大佬评论区给我建议和意见. 1. 组件化需要提升渲染性能的组件,例如触摸屏显示每个商品下单数量的商品列表 避免不必要地呈现组件子树, 执…

基于Springboot的房屋租赁管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的房屋租赁管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

域控安全 ----> Ntds.dit文件抓取

大家还记得内网渗透的初衷吗&#xff1f;&#xff1f;&#xff1f; 找到域馆&#xff0c;拿下域控&#xff01;&#xff01; 拿下了域控就是拿下了整个域&#xff01;&#xff01; 但是大家知道拿下域环境之后应该怎么操作吗(灵魂拷问)&#xff1f;&#xff1f;&#xff1f; …

OpenLayers入门①(引入的是一个高德地图)

OpenLayers入门&#xff08;一&#xff09; - 知乎 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&qu…

9种单片机常用的软件架构

长文预警&#xff0c;加代码5000多字&#xff0c;写了4个多小时&#xff0c;盘软件架构&#xff0c;这篇文章就够了! 可能很多工程师&#xff0c;工作了很多年&#xff0c;都不会有软件架构的概念。 因为我在做研发工程师的第6年&#xff0c;才开始意识到这个东西&#xff0c;在…

《MySQL45讲》读书笔记

重建表 alter table t engine InnoDB&#xff08;也就是recreate&#xff09;&#xff0c;而optimize table t 等于recreateanalyze&#xff0c;让表大小变小 重建表的执行流程 建立一个临时文件&#xff0c;扫描表 t 主键的所有数据页&#xff1b;用数据页中表 t 的记录生…

前端HTML5学习2(新增多媒体标签,H5的兼容性处理)

前端HTML5学习2新增多媒体标签&#xff0c;H5的兼容性处理&#xff09; 分清标签和属性新增多媒体标签新增视频标签新增音频标签新增全局属性 H5的兼容性处理 分清标签和属性 标签&#xff08;HTML元素&#xff09;和属性&#xff0c;标签定义了内容的类型或结构&#xff0c;而…

Django后台项目开发实战二

我们的需求是开发职位管理系统 三个功能&#xff1a; 管理员发布职位候选人能浏览职位用户能投递职位 第二阶段 创建应用 jobs&#xff0c;实现职位数据的建模 python manage.py startapp jobs 然后再 setting .py 注册应用&#xff0c;只需添加应用名称到最后一行 INST…

探索设计模式的魅力:分布式模式让业务更高效、更安全、更稳定

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索分布式模式之旅✨ 在数字化时代&#xff0c;企业面临着前所未有的挑战和机遇。…

docker挂载数据卷-以nginx为例

目录 一、什么是数据卷 二、数据卷的作用 三、如何挂载数据卷 1、创建nginx容器挂载数据卷 2、查看数据卷 3、查看数据卷详情 4、尝试在宿主机修改数据卷 5、查看容器内对应的数据卷目录 6、 访问nginx查看效果 ​​​​​​​一、什么是数据卷 挂载数据卷本质上就是实…

谷歌上架,为什么会触发填表单,可以避免吗?怎么填表单可以提高通过率?

在谷歌上架过程中&#xff0c;相信大部分开发者都有收到过谷歌发来表单填写的邮件通知&#xff0c;要求开发者们在14天内根据表单要求回复关于应用部分情况。邮件如图&#xff1a; 根据触发填表单的开发者分享的经验来看&#xff0c;填完表之后出现的情况不尽相同&#xff0c;且…

WDS+MDT网络启动自动部署windows(十五)使用it天空万能驱动

简介: 虽然我们可以使用dism这样的工具来备份驱动,并通过适当的厂家、型号来区分并自动注入驱动,它没万能驱动用着方便呀,还得去备份。 本文目标:在MDT部署时使用it天空的万能驱动。 下载 或许是我脑子坏掉了,印象中不是这个域名。 IT天空 - 新的十年,新的天空 (itsk.co…

农作物害虫检测数据集VOC+YOLO格式18975张97类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;18975 标注数量(xml文件个数)&#xff1a;18975 标注数量(txt文件个数)&#xff1a;18975 标…