rust学习十、非常处置惩罚(错误处置惩罚)

打印 上一主题 下一主题

主题 914|帖子 914|积分 2742

在册本中,中文译者翻译为错误,这是因为原文是"Error"。
但在许多语言中,都是书写为非常。
一、概述

rust的错误处置惩罚与众不同,前文已经提及:大家称为非常,它称为错误。

 
不可规复的错误,可以大要称为panic(恐慌)! 太率性了....
那么我们的问题是:除了一些的确不可处置惩罚的非常,rust是否也和大部分语言那样利用try catch来捕获和跳过?
所谓的不可规复错误,实在也可以被try catch处置惩罚?
 
二、用panic!宏处置惩罚错误

不可规复错误发生的时候的通常表现:会打印出一个错误信息,展开并整理栈数据,然退却出
通过一个环境变量,可以让 Rust 在 panic 发生时打印调用堆栈(call stack)以便于定位 panic 的缘故起因.
 
两种退出方式

  • abort- 粗暴退出,让操纵系统收拾残局
  • 回溯栈并整理它碰到的每一个函数的数据。如果需要查看堆栈,可以把环境变量RUST_BACKTRACE设置为不是0即可
设置退出方式
Cargo.toml中设置,如下:
  1. [profile.release]
  2. panic = 'abort'
复制代码
上文中,panic还可以是设置为unwind,这是默认的
上例是release,如果想在调试的时候,那么可以添加profile.dev
更多的配置,可以参考 https://www.rustwiki.org.cn/zh-CN/cargo/index.html
 
触发方式

  • 直接调用panic!宏

  • 一些可能导致不可规复的错误,例如除以0,越绝访问向量
 
示例一、直接触发

 输出一大堆!!!
示例二、越界访问

输出太多,截取了比较又意义的部分:已经充足明白那里发生错误的。
毫无疑问,对于第二种情况,在其它语言种,一样平常简单try catch就可以处置惩罚了!
三、用Result处置惩罚可规复错误

Resutt是什么
一个枚举范例,类似Option。
有两个成员Ok,Err
和Option的Some,None一样,Ok,Err也是可以直接利用,不需要书写前缀,因为它们都在prelude中导入了。
注意:prelude是序章的意思,可以理解为rust为每一个应用自动导入的部分。
 
处置惩罚Result,处置惩罚错误范例
由于Result是Option,以是,可以这样利用:
  1. use std::fs::File;
  2. use std::io::ErrorKind;
  3. fn main() {
  4.     let greeting_file_result = File::open("hello.txt");
  5.     let greeting_file = match greeting_file_result {
  6.         Ok(file) => file,
  7.         Err(error) => match error.kind() {
  8.             ErrorKind::NotFound => match File::create("hello.txt") {
  9.                 Ok(fc) => fc,
  10.                 Err(e) => panic!("Problem creating the file: {e:?}"),
  11.             },
  12.             other_error => {
  13.                 panic!("Problem opening the file: {other_error:?}");
  14.             }
  15.         },
  16.     };
  17. }
复制代码
 
大概
  1. use std::fs::File;
  2. use std::io::ErrorKind;
  3. fn main() {
  4.     let greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
  5.         if error.kind() == ErrorKind::NotFound {
  6.             File::create("hello.txt").unwrap_or_else(|error| {
  7.                 panic!("Problem creating the file: {:?}", error);
  8.             })
  9.         } else {
  10.             panic!("Problem opening the file: {:?}", error);
  11.         }
  12.     });
  13. }
复制代码
 
失败的两种处置惩罚:unwrap,expect
  1. use std::fs::File;
  2. fn main() {
  3.     let greeting_file = File::open("hello.txt").unwrap();
  4.     let greeting_file2 = File::open("hello.txt")
  5.         .expect("hello.txt should be included in this project");
  6. }
复制代码
unwrap和expect的区别在于:后者会在触发错误的时候,直接打印参数值。
expect方法内部大要是这样的:
  1.     #[inline]
  2.     #[track_caller]
  3.     #[stable(feature = "result_expect", since = "1.4.0")]
  4.     pub fn expect(self, msg: &str) -> T
  5.     where
  6.         E: fmt::Debug,
  7.     {
  8.         match self {
  9.             Ok(t) => t,
  10.             Err(e) => unwrap_failed(msg, &e),
  11.         }
  12.     }
复制代码
 
逻辑:正常就返回值、不正常的则返回一个非常(不可规复的错误,退出)。
 
3.1传播错误-如那边理错误


在大部分的语言中,有两种方式:继续抛出大概捕获之后做其它处置惩罚,例如java就是这样处置惩罚的。
这个内容比较多,以是单独一个小章节说明:

  • 通例处置惩罚-根据result结果返回需要的内容
  • 利用?简化处置惩罚
  • 不是任何地方都可以用?
  • 让main()函数可以支持?
  • Box
通例处置惩罚-这个没有什么好说的。
利用?简化处置惩罚
 
1.正常代码
  1. use std::fs::File;
  2. use std::io::{self, Read};
  3. fn read_username_from_file() -> Result<String, io::Error> {
  4.     let username_file_result = File::open("hello.txt");
  5.     let mut username_file = match username_file_result {
  6.         Ok(file) => file,
  7.         Err(e) => return Err(e),
  8.     };
  9.     let mut username = String::new();
  10.     match username_file.read_to_string(&mut username) {
  11.         Ok(_) => Ok(username),
  12.         Err(e) => Err(e),
  13.     }
  14. }
复制代码
 
 
2.简化代码-1
  1. use std::fs::File;
  2. use std::io::{self, Read};
  3. fn read_username_from_file() -> Result<String, io::Error> {
  4.     let mut username_file = File::open("hello.txt")?;
  5.     let mut username = String::new();
  6.     username_file.read_to_string(&mut username)?;
  7.     Ok(username)
  8. }
复制代码
 
?这里表示 match xxxx 一段内容。如果出现非常,已经退出了。
 
3. 继续简化的代码_2
  1. use std::fs::File;
  2. use std::io::{self, Read};
  3. fn read_username_from_file() -> Result<String, io::Error> {
  4.     let mut username = String::new();
  5.     File::open("hello.txt")?.read_to_string(&mut username)?;
  6.     Ok(username)
  7. }
复制代码
 
这里主要利用链式写法简化了。毫无疑问,这个链式的还是比较受到欢迎的!!!
 
哪里不能用?
函数的返回值不同于?
最典型例子:
  1. use std::fs::File;
  2. fn main() {
  3.     let greeting_file = File::open("hello.txt")?;
  4. }
复制代码
 
这是因为main的返回范例是()    --  rust的什么都奇怪的很,虽然最内核大家都差不多。
让main支持?
有什么惊人之举吗?没有,就是修改返回范例。
  1. use std::error::Error;
  2. use std::fs::File;
  3. fn main() -> Result<(), Box<dyn Error>> {
  4.     let greeting_file = File::open("hello.txt")?;
  5.     Ok(())
  6. }
复制代码
 
四、要不要panic!宏

 原文说了一堆口水话,对于有经验的工程师而言,没有什么价值。略!
五、小结


  • rust的错误处置惩罚和其它部分一样,力图做到与众不同- Error,panic!、Ok、Err、?、Box 这是凭空多出来的一些新概念(老东西换新的名称)
  • 暂时没有介绍如何让所谓的不可规复错误编程可以忽略的非常 --类似越界访问,在其它语言再正常不外了
  • 利用Resut和?某种程度上,会让代码看起来比一些语言悦目一些(仅仅是悦目而已)
  • 注意非常处置惩罚原则。 大概注意团队中的统一处置惩罚原则
  • 一个最重要的内容本章并没有提到:发生致命错误的时候,如何避免退出。这种要求非经常见,例如越界访问。但这个应该是肯定有的,只是本章并没有提到。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表