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

导航

  • 一、背景
  • 二、实践
    • 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.mzph.cn/diannao/6892.shtml

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

相关文章

LeetCode 142.环形链表Ⅱ

题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内…

速卖通自养号测评技术策略与实战指南

速卖通自养号测评是一个涉及多个步骤和细节的过程&#xff0c;以下是一些关键步骤和注意事项&#xff1a; 1. 准备资源和环境&#xff1a; 测评养号系统&#xff1a;确保账号的权重稳定运营与账号便捷的管理。 海外纯净IP资源&#xff1a;为账号提供稳定的网络环境&#x…

AI新突破:多标签预测技术助力语言模型提速3倍

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; 引言&#xff1a;多标签预测的新视角 在人工智能领域&#xff0c;尤其是在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;预测模型的训练方法一直在…

地下管线管网三维参数化建模软件MagicPipe3D V3.5

经纬管网建模系统MagicPipe3D&#xff08;www.magic3d.net&#xff09;自主安全可控&#xff0c;本地离线参数化构建三维管网模型&#xff08;管道、接头、附属物等&#xff09;&#xff0c;输出标准3DTiles、Obj等格式&#xff0c;支持Cesium、Unreal、Unity等引擎可视化查询分…

【TypeScript类简介以及使用方法】

TypeScript 引入了类的概念,允许使用面向对象的编程范式。类是对象的模板或蓝图,它定义了一组属性和方法,这些属性和方法被对象所共享。在 TypeScript 中,类提供了更结构化、可维护且可重用的代码方式。 TypeScript 类简介 属性:类中的变量称为属性(也称为字段或成员变量…

【mysql】深入探索mysql中的各种约束条件

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Java | Spring框架 | Bean的装配之XML配置

Spring | Bean的装配 之XML配置 在Spring框架中&#xff0c;Bean的装配是指将Bean定义和配置信息加载到Spring容器中&#xff0c;以便容器能够管理这些Bean。 Spring支持多种装配方式&#xff0c;其中XML配置是传统但依然有效的方式。 一、 使用XML配置文件定义Bean XML配置…

16、Python:函数定义

Python中的函数是组织好的&#xff0c;可重复使用的&#xff0c;用来实现单一&#xff0c;或相关联功能的代码段。它们能提高代码的模块性&#xff0c;和代码复用率。你可以将功能性代码块定义为函数&#xff0c;并在需要时调用它们。 函数定义 在Python中&#xff0c;def关键…

知识图谱和大语言模型的共存之道

导读 知识图谱和大型语言模型都是用来表示和处理知识的手段。大模型补足了理解语言的能力&#xff0c;知识图谱则丰富了表示知识的方式&#xff0c;两者的深度结合必将为人工智能提供更为全面、可靠、可控的知识处理方法。在这一背景下&#xff0c;OpenKG组织新KG视点系列文章—…

构建第一个ArkTS应用之@管理应用拥有的状态概述

上一个章节中介绍的装饰器仅能在页面内&#xff0c;即一个组件树上共享状态变量。如果开发者要实现应用级的&#xff0c;或者多个页面的状态数据共享&#xff0c;就需要用到应用级别的状态管理的概念。ArkTS根据不同特性&#xff0c;提供了多种应用状态管理的能力&#xff1a; …

还有谁……想知道“线下与线上布局之间的本质区别”

还有谁……想知道 线下与线上布局之间的本质区别 hello,亲爱的你们好.… 我是你们的好朋友,正博,今天是非常特殊的一天,给每一位读者准备了一份特殊的神秘礼物…… 在分享【特殊礼物】之前,请允许我分享一下《线下营销与线上销售的9大核心差异》…… 1、注意力; 2、销…

浪漫编码:手把手教你实现校园表白墙功能

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;浪漫编码&#xff1a;手把手教你实现校园表白墙功能 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 这里写目录标题 表白墙数据准备引入MyBatis和MySQL驱动依赖…

音视频开发2 音频基础

基本概念 三巨头&#xff1a;采样率、采样格式&#xff0c;声道数与声道布局、 PCM、音质、音频编码格式、音频封装格式 采样率&#xff1a; 每秒采集的样本数量 我们知道声音是连续的一段波&#xff0c; 模拟信号的波形是无限光滑的&#xff0c;可以看成由无数个点组成&am…

华为OD机试【路灯照明问题】(java)(100分)

1、题目描述 在一条笔直的公路上安装了N个路灯&#xff0c;从位置0开始安装&#xff0c;路灯之间间距固定为100米。 每个路灯都有自己的照明半径&#xff0c;请计算第一个路灯和最后一个路灯之间&#xff0c;无法照明的区间的长度和。 2、输入描述 第一行为一个数N&#xff…

中霖教育:哪些地区的一级造价师考试不查社保?

关于一级造价师考试是否查社保的问题&#xff0c;不同地区的规定不一样&#xff0c;部分地区要求社保缴纳时间为1年&#xff0c;部分地区要求6个月&#xff0c;具体还要以资格审核为准。 不用查社保的省份&#xff1a; 江苏、浙江、广东、海南、吉林、黑龙江、内蒙古、山西、…

生信软件16 - 常规探针设计软件mrbait

1. mrbait安装 mrbait支持linux和macOS系统&#xff0c;测试安装Python版本 3.6.15。 # conda安装 conda install mrbait -c tylerkchafin -c bioconda -c conda-forge# github安装 git clone https://github.com/tkchafin/mrbait.git cd mrbait python ./setup.py install# …

Oracle 23ai 发布,国产数据库们都沉默了

几天前&#xff0c;全球最大的数据库软件公司 Oracle 发布了最新版的 Oracle Database 23ai &#xff0c;集成了最新的 AI Vector Search&#xff08;AI 向量搜索引擎&#xff09;&#xff0c;允许根据概念内容轻松搜索存储在任务关键型数据库中的文档、图像和关系数据&#xf…

一文学会最强大的 node.js 后端框架 nest.js

文章目录 nest cli项目基本结构IOC & DI基础注册值注册时 key 的管理动态注册类工厂函数方式注册设置别名导出 provider 模块功能模块模块的导入导出模块类中使用注入全局模块动态模块 中间件定义中间件注册中间件MiddlewareConsumer 类全局中间件 异常过滤器抛出异常自定义…

社交媒体数据恢复:batchat

蝙蝠聊天数据恢复方法 1. 数据恢复的基本原理 蝙蝠聊天的聊天记录一旦删除是不能够恢复的。这是因为蝙蝠聊天的聊天记录是保存于本地的&#xff0c;一旦删除&#xff0c;就如同在电脑或手机上删除文件一样&#xff0c;数据不会存储在服务器端。这意味着&#xff0c;如果你删除…

vue computed的缓存在哪里

在 Vue 中&#xff0c;计算属性的缓存存在于计算属性本身所属的组件实例中。 具体来说&#xff0c;缓存是作为组件实例的一部分而存在的&#xff0c;在组件被销毁时&#xff0c;缓存也会随之被销毁。 当组件实例被创建时&#xff0c;Vue 会为每个计算属性创建一个闭包&#x…