rust 处理错误,不使用 try catch, 而是使用 Result<T, E>。

简单的处理rust错误

在各种关于rust错误处理的文档中,为了解释清楚其背后的机制,看着内容很多,不好理解。

比如我们写一个方法,读取文件内容:

fn read_file_to_string(file_path: String) -> Result<String, io::Error>{
let mut file = File::open(file_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}

上面的代码,当文件不存在的时候,也可以很好的返回异常信息。

调用代码:

    let r = read_file_to_string(r"d:\1111.txt".to_string());
match r {
Ok(str) => println!("OK: {str}"),
Err(e) => println!("Error: {e}"),
};

如果文件不存在,会输出信息:

这个异常处理的过程不复杂,分为三步:

  1. 自定义的函数要返回Result<T,E>,

  2. 返回Result的函数时,后面加上问号,

  3. 在最上层,使用match处理结果。

但是这样是不够的,如果在一个大项目中,我们很难找到是哪个文件缺失了,rust不像c#那样,可以很容易的获取到出现问题的代码行数、类和方法名等。

最直观的方法是,在异常信息里,带上文件名。

自定义错误,带上文件名

rust自定义错误分为三步:

1)定义错误类型

2)实现Error特征(trait)

  1. 实现Display特征

自定义错误的类型是enum, 和其他语言相比,这有点奇怪。 代码如下:

// 定义自定义错误类型
#[derive(Debug)]
pub enum MyError {
FileOpenError(String),
ParseError(String),
Common(String),
} // 实现Error特质
impl Error for MyError {} // 实现Display特质以便打印错误信息
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MyError::FileOpenError(msg) => write!(f, "Failed to open file: {}", msg),
MyError::ParseError(msg) => write!(f, "Parse error: {}", msg),
MyError::Common(msg) => write!(f, "Other error: {}", msg),
}
}
}

这时,读取文件的函数代码要改成这样:

fn read_file_to_string(file_path: String) -> Result<String, MyError>{
let r = File::open(file_path.clone());
match r {
Ok(mut file) => {
let mut contents = String::new();
let r2 = file.read_to_string(&mut contents);
match r2 {
Ok(size) => return Ok( contents),
Err(e) => return Err(MyError::Common(format!("{e} 文件: {file_path}"))),
}
},
Err(e) => {
return Err(MyError::FileOpenError(format!("{e} 文件: {file_path}")));
},
}
}

代码变得很啰嗦,好在能比较好的显示错误了:

自定义错误的三部曲,虽然有点长,但是这是项目的公共代码,还是可以忍受的。读取文件的代码,和 c#比起来,真的太罗嗦了。

简化通用异常处理

读取文件内容的函数,代码罗嗦的原因是,异常类型通过问号匹配到自定义的MyError很麻烦。

这里我们采用一种更通用的方式,来处理异常:

1) 重新第一自定义异常,并且提供其他异常向自定义异常转换的方法

custom_error.rs:

use std::error::Error;
use std::fmt;
use std::fmt::Display; // 自定义错误类型,包含文件路径信息
#[derive(Debug)]
pub struct MyError {
msg: String,
source: String,
} // 为自定义错误类型实现Error trait
impl Error for MyError {} // 实现Display trait,以便于打印错误信息
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}: {}", self.source, self.msg)
}
} pub fn convert_error(msg:String, err: String) -> MyError {
MyError {
msg: msg ,
source: err.to_string(),
}
} // 定义一个新的trait
pub trait MyErrorExtension<T> {
fn ex_err(self, msg:&String)-> Result<T, MyError>;
} // 为Result<T,E>类型实现MyExtension trait
impl<T,E:Display> MyErrorExtension<T> for Result<T,E> {
fn ex_err(self, msg:&String) -> Result<T, MyError> {
match self {
Ok(t) => Ok(t),
Err(e) => Err(MyError{msg:msg.to_string(), source: e.to_string()}),
}
}
}

2) 定义带有通用异常处理能力的函数的示例:

fn read_file_to_string(file_path: String) -> Result<String, MyError>{
let context_info = format!("文件路径: {file_path}");
fs::metadata(&file_path).ex_err(&context_info)?;
let mut file = File::open(&file_path).ex_err( &context_info)?;
let mut contents = String::new();
file.read_to_string(&mut contents).ex_err(&context_info)?;
Ok(contents)
}

以打开文件的方法为例,原本的调用是:

let mut file = File::open(&file_path)?;

新的调用,后面附加了重要的上下文信息,并且把异常类型转换为MyError:

let mut file = File::open(&file_path).ex_err( &context_info)?;

通过扩展方法ex_err, 达到了我们的目的。

Rust 错误处理的更多相关文章

  1. 航空概论(历年资料,引之百度文库,PS:未调格式,有点乱)

    航空航天尔雅 选择题1. 已经实现了<天方夜谭>中的飞毯设想.—— A——美国2. 地球到月球大约—— C 38 万公里3. 建立了航空史上第一条定期空中路线—— B——德国4. 对于孔明 ...

  2. Rust语言——无虚拟机、无垃圾收集器、无运行时、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争

    2006年,编程语言工程师Graydon Hoare利用业余时间启动了Rust语言项目.该项目充分借鉴了C/C++/Java/Python等语言的经验,试图在保持良好性能的同时,克服以往编程语言所存在 ...

  3. Rust中的错误处理

    Result & Panic 这次讲得详细,从错误的来历及简写过程, 都写明白了, 先浅,再深,先深,再浅, 反复之, 学习王道~ use std::fs::File; //use std:: ...

  4. Rust语言的多线程编程

    我写这篇短文的时候,正值Rust1.0发布不久,严格来说这是一门兼具C语言的执行效率和Java的开发效率的强大语言,它的所有权机制竟然让你无法写出线程不安全的代码,它是一门可以用来写操作系统的系统级语 ...

  5. Rust初步(七):格式化

    在Rust中,如果要进行屏幕输出,或者写入到文件中,需要对数据进行格式化.这一篇总结一下它所支持的几种格式化方式. 这篇文章参考了以下官方文档,不过,按照我的风格,我还是会突出于C#语言的比较,这样可 ...

  6. Rust初步(六):在C#中使用Rust组件

    上一篇文章,我们通过实例比较了一下C#和Rust的性能表现,应该说在Release模式下面,Rust进行计算密集型的运算还是有些比较明显的优势的.那么,我们有没有可能,在C#中做一些快速应用开发,而一 ...

  7. Rust初步(四):在rust中处理时间

    这个看起来是一个很小的问题,我们如果是在.NET里面的话,很简单地可以直接使用System.DateTime.Now获取到当前时间,还可以进行各种不同的计算或者输出.但是这样一个问题,在rust里面, ...

  8. Rust初步(二):使用Visual Studio Code编写Rust程序(猜猜看游戏)

    我是照着下面这篇帮助文档,完成了第一个完整的Rust程序: 猜猜看 游戏 http://kaisery.gitbooks.io/rust-book-chinese/content/content/3. ...

  9. Rust: lifetime

    Rust的lifetime算是它最重要的特性之一,也不大好理解,特别是官方文档的介绍有些太过简略,容易让人误解. 这篇文章: Rust Lifetimes 应该可以解答很多人疑惑,特别是有关lifet ...

  10. Rust: move和borrow

    感觉Rust官方的学习文档里关于ownship,borrow和lifetime介绍的太简略了,无法真正理解这些语法设计的原因以及如何使用(特别是lifetime).所以找了一些相关的blog来看,总结 ...

随机推荐

  1. IDEA MyBatis Log 插件,打印SQL语句

    打开Settings->plugins 搜索插件 MyBatis Log点击安装,完成后重启IDEA即可. 点击Tools,选择 MyBatis Log Plugin ,会在下方打开一个窗口,这 ...

  2. 8 JavaScript函数

    8 JavaScript函数 在JS中声明函数和python差不多. 也要有一个关键字顶在前面. python是def, 到了JS里换成了function, 只不过在JS中没有像python那么死板, ...

  3. 【直播回顾】如何成为一名优秀的OpenHamrony贡献者?

    5月18日晚上19点,战"码"先锋第一期直播<如何成为一名优秀的OpenHamrony 贡献者?>,在OpenHarmony社群内成功举行. 本期课程,由润和资深软件开 ...

  4. HE琥珀虚颜破解自由安装程序教程(001)

    HE琥珀虚颜破解自由安装程序教程(001) 前言 自从狗尾草跑路后,HE琥珀就没法用了,当前APP还没法破解,但是笔者找到了HE琥珀存在的一些漏洞,可以实现安装自己的APP. 所需工具 所需工具 1. ...

  5. .NET MAUI开源免费的UI工具包 - Uranium

    前言 一直有小伙伴在微信公众号后台留言让我分享一下.NET MAUI相关的UI框架,今天大姚分享一个.NET MAUI开源.免费的UI工具包:Uranium. Uranium介绍 Uranium是一个 ...

  6. 56.5K star的gpt4free开源项目到底真的假的?

    前言 这个项目是我很早之前就star,只是当时觉得有点天真,怎么会有那么多免费的好事情呢?然后就在清明节前夕,OpenAI 开放了免登录即可使用GPT-3.5的模型,那么势必很快就有了免费使用GPT- ...

  7. HarmonyOS实践之应用状态变量共享

      平时在开发的过程中,我们会在应用中共享数据,在不同的页面间共享信息.虽然常用的共享信息,也可以通过不同页面中组件间信息共享的方式,但有时使用应用级别的状态管理会让开发工作变得简单. 根据不同的使用 ...

  8. 如何用一行 CSS 实现 10 种现代布局

    现代 CSS 布局使开发人员只需按几下键就可以编写十分有意义且强大的样式规则.上面的讨论和接下来的帖文研究了 10 种强大的 CSS 布局,它们实现了一些非凡的工作. 01. 超级居中:place-i ...

  9. vue-cli4.0 (vue3.0 的脚手架)

    前言: 这个搭建脚手架的话实际是我们创建一个新项目的第一步,当然,现在脚手架4.0都出来了,经过使用后发现跟我们之前的3.0使用方法是答题一样的,其中用vue-cli3.0来搭建我们的项目的话又分为两 ...

  10. PostgreSQL 14.4的安装以及使用以及一些安装的异常

    PostgreSQL 14的安装以及使用 因为公司的一些要求,可能要换数据库,虽然之前装过,但是版本感觉还是新一点比较好,所以重新装一下 首先下载文件,直接去官网下载就行 https://www.en ...