学习Rust第15天:错误处理

错误管理是Rust编程的重要组成部分,允许开发人员优雅地处理不可预见的事件。Rust有各种错误管理功能,包括用于故意程序崩溃的panic宏,用于描述操作结果的Result枚举,以及简单错误传播的操作符。使用这些方法和定制的错误类型,开发人员可以创建强大而可靠的软件,以正确地管理错误。了解错误处理系统的Rust开发人员可以构建更安全和更可维护的代码,从而提高其程序的整体质量和可靠性。

Introduction 介绍

Error handling basically means how to handle certain situations which are not optimal for your program to work in, there are some gracefully handleable errors
错误处理基本上意味着如何处理某些情况下,这是不是最佳的为您的程序的工作,有一些优雅的可删除的错误
If the error cannot be handled/recovered from we can call the panic macro and crash our program intentionally, We will also take a look at back tracing…
如果错误不能被处理/恢复,我们可以调用 panic 宏并故意崩溃我们的程序,我们还将看看回溯.

Panic Macro Panic宏

The panic macro is used when we want our program to crash on purpose, If an error cannot be handled gracefully or the program cannot recover from the error, we can call the panic macro by using the following syntax:
panic宏用于当我们希望我们的程序崩溃时,如果错误不能被优雅地处理或程序不能从错误中恢复,我们可以使用以下语法调用panic宏:

panic!(error_message: &str);

Example: 范例:

fn main(){panic!("This is a test panic");
}

Output: 输出量:

thread 'main' panicked at src/main.rs:2:3:
This is a test panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The panic message shows we can run the program with RUST_BACKTRACE=1 environment variable to get a backtrace
panic消息显示我们可以使用 RUST_BACKTRACE=1 环境变量运行程序以获得回溯

What is a backtrace? 什么是回溯?

A backtrace is a trace of all the functions called before the code panicked let’s take a look at that with a slightly accurate example:
回溯是在代码死机之前调用的所有函数的跟踪,让我们用一个稍微准确的例子来看看:

fn main(){a();
}fn a(){b();
}
fn b(){panic!("Function panicked");
}

Output: 输出量:

thread 'main' panicked at src/main.rs:9:5:
Function panicked
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Output with RUST_BACKTRACE=1 : 输出 RUST_BACKTRACE=1 :

thread 'main' panicked at src/main.rs:9:5:
Function panicked
stack backtrace:0: rust_begin_unwindat /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:51: core::panicking::panic_fmtat /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:142: error_handling::bat ./src/main.rs:9:53: error_handling::aat ./src/main.rs:6:54: error_handling::mainat ./src/main.rs:2:55: core::ops::function::FnOnce::call_onceat /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

In this example we can see that, main() calls a function a() , then a() calls b() which crashes the program and we can clearly follow through what happens in the code using the backtrace.
在这个例子中,我们可以看到, main() 调用了一个函数 a() ,然后 a() 调用了 b() ,这使程序崩溃,我们可以清楚地通过使用回溯跟踪来跟踪代码中发生的事情。

Result enum 结果枚举

The Result enum in Rust simplifies error handling by providing a way to represent the success or failure of operations, For example opening a file may fail if the file does not exist and that would result in an error.
Rust中的 Result 枚举通过提供一种表示操作成功或失败的方法来简化错误处理,例如,如果文件不存在,则打开文件可能会失败,这将导致错误。

The result enum looks something like this.
结果枚举看起来像这样。

match Result(Ok(arguments) => {},Err(error) => {},
);

Let’s take a better look in an example…
让我们更好地看看一个例子.

use std::fs::File;
use std::io::prelude::*;fn main() {// Attempt to open a filematch File::create("example.txt") {Ok(mut file) => {// File created successfully, write content to itif let Err(e) = file.write_all(b"Hello, World!") {println!("Failed to write to file: {}", e);} else {println!("Data successfully written to file.");}}Err(e) => {// Failed to create file, handle the errorprintln!("Failed to create file: {}", e);}}
}
  • The code attempts to create a file named “example.txt” using File::create().
    代码尝试使用 File::create() 创建名为“example.txt”的文件。
  • It matches the result of the file creation operation using a match statement.
    它使用 match 语句匹配文件创建操作的结果。
  • If the file is successfully created (Ok(mut file)), it proceeds to write "Hello, World!" to the file.
    如果文件成功创建( Ok(mut file) ),它会继续写入“Hello,World!”的文件。
  • If writing to the file fails (Err(e)), it prints an error message.
    如果写入文件失败( Err(e) ),它将打印一条错误消息。
  • If creating the file fails (Err(e)), it prints an error message, indicating the reason for the failure.
    如果创建文件失败( Err(e) ),它将打印一条错误消息,指出失败的原因。

Output : 输出量:

Data successfully written to file.

example.txt : example.txt:

Hello, World!

Instead of using the match expression we could have also called the unwrap() or expect() method to do this as well.
除了使用 match 表达式,我们还可以调用 unwrap() 或 expect() 方法来完成这一任务。

The unwrap() method is used to retrieve the value from a Result enum, panicking if it encounters an Err, while expect() provides similar functionality but allows for a custom error message to be provided in case of failure.
unwrap() 方法用于从 Result 枚举中检索值,如果遇到 Err 则会出现恐慌,而 expect() 提供了类似的功能,但允许在失败时提供自定义错误消息。

Error propagation 误差传播

In Rust, error propagation is accomplished by propagating errors up the call stack via the Result type, allowing for modular error handling while retaining abstraction levels. It encourages centralized error handling, allowing for uniform tactics throughout the program, and improves debugging by giving contextual information about problem causes. This strategy guarantees graceful failure handling and helps to build strong and maintainable software.
在Rust中,错误传播是通过Result类型将错误传播到调用堆栈来完成的,允许模块化错误处理,同时保留抽象级别。它鼓励集中的错误处理,允许在整个程序中使用统一的策略,并通过提供有关问题原因的上下文信息来改进调试。这种策略保证了优雅的故障处理,并有助于构建强大和可维护的软件。

Let’s take a look at an example
我们来看一个例子

use std::fs::File;
use std::io::{self, Write};fn write_to_file(data: &[u8]) -> io::Result<()> {let mut file = match File::create("example.txt") {Ok(file) => file,Err(e) => return Err(e),};match file.write_all(data) {Ok(_) => Ok(()),Err(e) => Err(e),}
}fn main() {let data = b"Hello, World!";match write_to_file(data) {Ok(()) => println!("Data successfully written to file."),Err(e) => println!("Failed to write to file: {}", e),}
}
  • The write_to_file function attempts to create a file named "example.txt" and write data to it.
    write_to_file 函数尝试创建一个名为“example.txt”的文件并向其中写入数据。
  • Inside write_to_file, a match statement is used to handle the result of File::create. If the file creation is successful, the file handle is stored in file. If it fails, the error is returned early.
    在 write_to_file 中,一个 match 语句用于处理 File::create 的结果。如果文件创建成功,则文件句柄存储在 file 中。如果失败,则会提前返回错误。
  • Another match statement is used to handle the result of write_all. If the write operation is successful, Ok(()) is returned. If it fails, the error is returned.
    另一个 match 语句用于处理 write_all 的结果。如果写操作成功,则返回 Ok(()) 。如果失败,则返回错误。
  • In the main function, the result of write_to_file is matched again to determine whether the operation was successful or not.
    在 main 函数中,再次匹配 write_to_file 的结果以确定操作是否成功。

This code can be made shorter and easier to read using the ? operator.
使用 ? 操作符可以使这段代码更短,更容易阅读。

The ? operator in Rust is a shorthand for error propagation. It can be used within functions that return a Result type, simplifying error handling by automatically unwrapping the Ok variant and returning the contained value or propagating the Err variant.
Rust中的 ? 操作符是错误传播的简写。它可以在返回 Result 类型的函数中使用,通过自动展开 Ok 变量并返回包含的值或传播 Err 变量来简化错误处理。

use std::fs::File;
use std::io::{self, Write};fn write_to_file(data: &[u8]) -> io::Result<()> {let mut file = File::create("example.txt")?;file.write_all(data)?;Ok(())
}fn main() -> io::Result<()> {let data = b"Hello, World!";write_to_file(data)?;println!("Data successfully written to file.");Ok(())
}
  • The write_to_file function attempts to create a file named "example.txt" and write data to it.
    write_to_file 函数尝试创建一个名为“example.txt”的文件并向其中写入数据。
  • The ? operator is used after each potentially error-prone operation (File::create and write_all). If an error occurs at any step, it will be propagated up the call stack, and the function will return early with that error.
    ? 操作符用于每个可能出错的操作( File::create 和 write_all )之后。如果在任何步骤中发生错误,它将在调用堆栈中向上传播,并且函数将提前返回该错误。
  • In the main function, error propagation is also used, allowing any error from write_to_file to be handled gracefully, and if successful, it prints a success message.
    在 main 函数中,还使用了错误传播,允许优雅地处理来自 write_to_file 的任何错误,如果成功,它会打印一条成功消息。

Overall, the ? operator streamlines error handling in Rust code by reducing boilerplate and improving readability.
总的来说, ? 操作符通过减少样板和提高可读性来简化Rust代码中的错误处理。

Custom types for error handling
用于错误处理的自定义类型

We created a guessing game in the start of this series, if you haven’t read that, click here
我们在本系列开始时创建了一个猜谜游戏,如果您还没有阅读,请单击此处

In that we were simply taking the number from the user without any form of validation, although our guess was in the range 1..=100 . The user could input any number so let’s fix that?
因为我们只是简单地从用户那里获取数字,而没有任何形式的验证,尽管我们的猜测是在 1..=100 范围内。用户可以输入任何数字,让我们来解决这个问题吧?

pub struct Guess{value: i32,
}impl Guess {pub fn new(value: i32) -> Guess{if value < 1 || value > 100 {panic!("Value must be between 1 to 100, got {}", value);}Guess{ value }}pub fn value(&self) -> i32{self.value}
}

Now we can use this to improve our guessing game, let’s integrate this in the code…
现在我们可以用它来改进我们的猜谜游戏,让我们把它集成到代码中。

use std::io;
use std::cmp::Ordering;
use rand::Rng;pub struct Guess{value: i32,
}impl Guess {pub fn new(value: i32) -> Guess{if value < 1 || value > 100 {panic!("Value must be between 1 to 100, got {}", value);}Guess{ value }}pub fn value(&self) -> i32{self.value}
}fn main() {println!("Guess the number!");let secret_number = rand::thread_rng().gen_range(1..=100);loop {println!("Please input your guess");let mut guess = String::new();io::stdin().read_line(&mut guess).expect("Failed to read line");let guess: i32 = match guess.trim().parse() {Ok(num) => num,Err(_) => continue,};let guess: Guess = Guess::new(guess);println!("Your guess: {}", guess.value);match guess.value().cmp(&secret_number) {Ordering::Less => println!("Too small!"),Ordering::Greater => println!("Too big!"),Ordering::Equal => {println!("You win!");break;},}}
}

Output: 输出量:

Guess the number!
Please input your guess
100
Your guess: 100
Too big!
Please input your guess
291
thread 'main' panicked at src/main.rs:12:7:
Value must be between 1 to 100, got 291

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/644189.html

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

相关文章

密码学 | Schnorr 协议:零知识身份证明和数字签名

&#x1f955;原文&#xff1a; Schnorr 协议&#xff1a;零知识身份证明和数字签名 &#x1f955;写在前面&#xff1a; 本文属搬运博客&#xff0c;自己留存学习。文中的小写字母表示标量&#xff0c;大写字母表示椭圆曲线中的点。 1 Schnorr 简介 Schnorr 由德国数学家和密…

GUI测试首推!TestComplete 帮助有效缩短 40-50% 测试时长!

TestComplete 是一款自动化UI测试工具&#xff0c;这款工具目前在全球范围内被广泛应用于进行桌面、移动和Web应用的自动化测试。 TestComplete 集成了一种精心设计的自动化引擎&#xff0c;可以自动记录和回放用户的操作&#xff0c;方便用户进行UI&#xff08;用户界面&…

数据结构之顺序表(java版)

目录 一.线性表 1.1线性表的概念 二.顺序表 2.1顺序表的概念 2.2顺序表的实现 1.顺序表的接口 1.2顺序表的功能实现 1.顺序表初始化 2.新增元素功能&#xff1a; 3.清空顺序表是否为空&&获取顺序表长度&&打印顺序表&#xff1a; 4.判断是否包含某个…

C语言 | Leetcode C语言题解之第47题全排列II

题目&#xff1a; 题解&#xff1a; int* vis;void backtrack(int* nums, int numSize, int** ans, int* ansSize, int idx, int* perm) {if (idx numSize) {int* tmp malloc(sizeof(int) * numSize);memcpy(tmp, perm, sizeof(int) * numSize);ans[(*ansSize)] tmp;return…

食用油5G智能工厂数字孪生可视化平台,推进食品制造业数字化转型

食用油5G智能工厂数字孪生可视化平台&#xff0c;推进食品制造业数字化转型。在食用油产业中&#xff0c;数字化转型已成为提升生产效率、优化供应链管理、确保产品质量和满足消费者需求的关键。食用油5G智能工厂数字孪生可视化平台作为这一转型的重要工具&#xff0c;正在推动…

四川赢涟电子商务有限公司是做什么的?

在当今数字化浪潮中&#xff0c;电子商务以其独特的魅力和无限潜力&#xff0c;成为了商业领域的新宠。而在这股潮流中&#xff0c;四川赢涟电子商务有限公司以其对抖音电商的深入研究和专业服务&#xff0c;成为了行业内的佼佼者。 一、深耕抖音&#xff0c;领跑电商新赛道 四…

隆道再次当选中招协招标采购数字化专委会执行主任单位

4月19日&#xff0c;中国招标投标协会招标采购数字化专业委员会换届会议暨第二届第一次工作会议在宁波召开。经过大会提名、审议和表决&#xff0c;北京隆道网络科技有限公司再次当选为招标采购数字化专委会执行主任单位。 中国招标投标协会招标采购数字化专业委员会&#xff0…

uView u-parse 在nvue页面中无作用踩坑

问题起因&#xff1a; 在uni-app开发的app nvue页面中有需要回显渲染字符串形式的富文本内容 但使用v-html和uniapp的rich-text组件都无法起到作用&#xff0c;就想到了使用uView中u-parse进行尝试。 uView我是使用uniApp插件市场导入的方式将插件导入项目的uni_modules中 …

上海·得物技术沙龙-「无线技术」专场报名开启!

本次无线沙龙聚焦于最新的技术趋势和实践&#xff0c;将在上海/线上为你带来四个令人期待的演讲话题&#xff0c;包括&#xff1a;《快手主App启动接口带宽优化实践》、《得物App视频体验优化实践》、《Chromium内核架构和网络库优化介绍》、《得物App发热监控实践》。相信这些…

聚观早报 | 百度地图V20正式发布;OPPO K12细节曝光

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月24日消息 百度地图V20正式发布 OPPO K12细节曝光 Meta宣布开放VR系统 三星 Galaxy Ring提供多种尺寸 Redmi …

【七】jmeter5.5+influxdb2.0+prometheus+grafana

参考文章&#xff1a;https://blog.csdn.net/wenxingchen/article/details/126892890 https://blog.csdn.net/Zuo19960127/article/details/119726652 https://blog.csdn.net/shnu_cdk/article/details/132182858 promethus参考 由于自己下载的是infuldb2.0&#xff0c;所以按照…

权益商城系统源码 现支持多种支付方式

权益商城系统源码&#xff0c;支持多种支付方式&#xff0c;后台商品管理&#xff0c;订单管理&#xff0c;串货管理&#xff0c;分站管理&#xff0c;会员列表&#xff0c;分销日志&#xff0c;应用配置。 上传到服务器&#xff0c;修改数据库信息&#xff0c;导入数据库&…