错误处理(9)

错误处理

    • 1.用panic!处理不可恢复的错误
      • 1.1对应panic时的栈展开或终止
      • 1.2使用panic!的backtrace
        • 1.尝试访问超越vector结尾的元素,这会造成panic!
        • 2.当设置RUST_BACKTRACE环境变量时panic!调用所生成的backtrace信息
    • 2.用Result处理可恢复的错误
      • 1.使用match表达式处理可能会返回的Result成员
      • 2.匹配不同的错误
        • 1.使用不同的方式处理不同类型的错误
        • 2.不同于使用match和Result<T,E>
      • 2.失败时panic的简写:unwrap 和 expect
        • 1.unwrap
        • 2.expect
      • 3.传播错误
        • 1.函数使用match将错误返回给代码调用者
      • 4.传播错误的简写: ?运算符
      • 5.使用fs::read_to_string而不是打开后读取文件
      • 6.哪些情况可以使用?运算符
        • 6.1尝试在返回()的main函数中使用?的代码不能编译
        • 6.2在Option<T>值上使用? 运算符
        • 6.3修改main返回Result<(),E>允许对Result值使用?运算符
    • 3.要不要panic!
      • 3.1错误处理指导原则
      • 3.2创建自定义类型进行有效性验证
        • 1.一个Guess类型,它只在位于1和100之间时才会继续

  • Rust将错误分为两个大类: 可恢复的不可恢复的

1.用panic!处理不可恢复的错误

  • 在实践中有两种方法造成panic:
    • 执行会造成代码panic的操作
    • 显式调用panic!宏
  • 通常情况下这些panic会打印一个错误信息,展开并清理数据,然后退出

1.1对应panic时的栈展开或终止

  • 当出现panic时,程序默认会开始展开,这意味着Rust会回溯栈并清理它遇到的每一个函数的数据,不过这个回溯并清理的过程有很多工作
  • 另一种选择是直接终止,这会不清理数据就退出程序
  • panic时通过在Cargo.toml的[profile]部分增加panic = 'abort',可以由展开切换为终止

1.2使用panic!的backtrace

1.尝试访问超越vector结尾的元素,这会造成panic!
fn main() {let v = vec![1,2,3];v[99];
}
  • C语言中,尝试读取数据结构之后的值是未定义行为;会得到任何对应数据结构中这个元素的内存位置的值,甚至是这些内存并不属于这个数据结构的情况,被称为缓冲区溢出,并可能导致安全漏洞
  • 为了保护程序远离这类漏洞,尝试读取一个索引不存在的元素,Rust会停止执行并拒绝继续
PS C:\Tools\devTools\vscode\code\rust\world_hello> cargo runCompiling world_hello v0.1.0 (C:\Tools\devTools\vscode\code\rust\world_hello)Finished dev [unoptimized + debuginfo] target(s) in 0.25sRunning `target\debug\world_hello.exe`
thread 'main' panicked at src\main.rs:3:6:
index out of bounds: the len is 3 but the index is 99
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\world_hello.exe` (exit code: 101)
2.当设置RUST_BACKTRACE环境变量时panic!调用所生成的backtrace信息
>$env:RUST_BACKTRACE=1; cargo run 
  • backtrace是一个指向到目前位置所有被调用的函数列表

2.用Result处理可恢复的错误

1.使用match表达式处理可能会返回的Result成员

use std::fs::File;
fn main() {let greeting_file_result = File::open("../Cargo.lock");let greeting_file = match greeting_file_result{Ok(file) =>file,Err(error)=>panic!("Problem opening the file: {:?}",error),};
}
enum Result<T,E>{Ok(T),Err(E),
}
  • 输出
thread 'main' panicked at src\main.rs:6:21:
Problem opening the file: Os { code: 2, kind: NotFound, message: "系统找不到指定的文件。" }
stack backtrace:0: std::panicking::begin_panic_handlerat /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library\std\src\panicking.rs:5971: core::panicking::panic_fmtat /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library\core\src\panicking.rs:72

2.匹配不同的错误

1.使用不同的方式处理不同类型的错误
use std::fs::File;
use std::io::ErrorKind;
fn main() {let greeting_file_result = File::open("../Cargo.lock");let greeting_file = match greeting_file_result{Ok(file) =>file,Err(error)=> match error.kind() {ErrorKind::NotFound =>match File::create("Cargo.lock") {Ok(fc) => fc,Err(e) => panic!("Problem creating the file: {:?}",e),},other_error =>{panic!("Problem opening the file: {:?}",other_error);}}};
}
enum Result<T,E>{Ok(T),Err(E),
}
2.不同于使用match和Result<T,E>
use std::fs::File;
use std::io::ErrorKind;
fn main() {let greeting_file_result = File::open("../Cargo.lock").unwrap_or_else(|error|{if error.kind() == ErrorKind::NotFound{File::create("../test.txt").unwrap_or_else(|error|{panic!("Problem creating the file: {:?}",error);})}else{panic!("Problem opening the file: {:?}",error);}});
}

2.失败时panic的简写:unwrap 和 expect

1.unwrap
  • match能够胜任它的工作,不过它可能有点冗长并且不总是能很好的表明其意图
  • Result<T, E>类型定义了很多辅助方法来处理各种情况
    • unwrap,Result值是成员Ok,unwrap会返回Ok中的值
    • Result是成员Err,unwrap会调用panic!
use std::fs::File;fn main() {let greeting_file_result = File::open("../Cargo.lock").unwrap();
}
2.expect
  • 使用expect而不是unwrap并提供了一个好的错误信息可以表明你的意图方便追踪panic的根源
use std::fs::File;fn main() {let greeting_file_result = File::open("../Cargo.lock").expect("Cargo.lock should be included in this project");
}
  • 生产级别的代码中,大部分选择expect

3.传播错误

  • 编写一个其实先会调用一些可能会失败的操作的函数时,除了在这个函数中处理错误外,还可以选择让调用者知道这个错误并决定该如何处理,这被称为传播错误
1.函数使用match将错误返回给代码调用者
use std::fs::File;
use std::io::{self,Read};
fn main() {read_username_from_file();
}
fn read_username_from_file() -> Result<String, io::Error>{let username_file_result = File::open("hello.txt");let mut username_file = match username_file_result{Ok(file) =>file,Err(e) => return Err(e),};let mut username = String::new();match username_file.read_to_string(&mut username){Ok(_) => Ok(username),Err(e) => Err(e),}
}

4.传播错误的简写: ?运算符

use std::fs::File;
use std::io::{self,Read};
fn main() {read_username_from_file();
}
fn read_username_from_file() -> Result<String, io::Error>{let mut username_file = File::open("hello.txt")?;let mut username = String::new();username_file.read_to_string(&mut username)?;//链式编程  同上// File::open("hello.txt")?.read_to_string(&mut username)?;Ok(username)
}

5.使用fs::read_to_string而不是打开后读取文件

use std::fs;
use std::io;
fn main() {read_username_from_file();
}
fn read_username_from_file() -> Result<String, io::Error>{fs::read_to_string("hello.txt")
}

6.哪些情况可以使用?运算符

  • ?运算符只能被用于返回值与?作用的值相兼容的函数
6.1尝试在返回()的main函数中使用?的代码不能编译
  • 这个错误指出在返回Result或者其它实现了FromResidual的类型的函数中使用?运算符
  • 错误信息也提到了?也可用于Option< T>值
use std::fs::File;fn main() {// 不能编译// let greeting_file = File::open("hello.txt")?;
}
6.2在Option值上使用? 运算符
fn last_char_of_first_line(text: &str) -> Option<char>{text().lines().next()?.chars().last()}
6.3修改main返回Result<(),E>允许对Result值使用?运算符
  • main函数也可以返回任何实现了 std::process::Termination trait的类型,它包含了一个返回ExitCode的report函数
  • main函数返回Result<(),E>,如果main返回Ok(())可执行程序以0值退出;如果main返回Err值则会以非零值退出
use std::fs::File;
use std::error::Error;
fn main() -> Result<(),Box<dyn Error>> {// Box<dyn Error>类型是一个trait对象let greeting_file = File::open("hello.txt")?;Ok(())
}

3.要不要panic!

3.1错误处理指导原则

  • 在当有可能会导致有害状态的情况下建议使用panic!
  • 有害状态是指当一些假设保证协议不可变性被打破的状态
  • 其他情况
    • 有害状态是非预期的行为,与偶尔会发生的行为相对
    • 在此之后的代码允许依赖于不处于这种有害状态,而不是在每一步都检查是否有问题
    • 没有可行的手段来将有害状态信息编码进所使用的类型中的情况

3.2创建自定义类型进行有效性验证

loop{let guess: i32 = match guess.trim().parse(){Ok(num) => num,Err(_) => countine,};if guess<1 || guess >100 {println!("The secret number will be between 1 and 100");continue;}match guess.cmp(&secret_number){}
}
1.一个Guess类型,它只在位于1和100之间时才会继续
pub struct Guess{value: i32,
}
impl Guess{pub fn new(value: i32)->Guess{if vaule < 1 || value >100 {panic!("Guess value must be between 1 and 100 ,got {}",value);}Guess {value}}// 这类方法有时被称为getter,目的就是返回对应字段的数据。 value字段是私有的pub fn value(&self) -> i32{self.value}}

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

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

相关文章

java并发-线程生命周期

文章目录 前言状态图状态变化说明补充说明 前言 线程的生命周期指的是线程从创建出来到最终消亡的整个过程&#xff0c;以及过程中的状态变化。 状态图 以下图用mermaid语法绘制&#xff1a; #mermaid-svg-32vKT6KmFdlYvCnr {font-family:"trebuchet ms",verdana,…

日期类 - Java

知道怎么查&#xff0c;怎么用即可&#xff0c;不用每个方法都背 日期类 第一代日期类方法演示 第二代日期类方法演示 第三代日期类前面两代日期类的不足分析第三代日期类常见方法方法演示 第一代日期类 Date类&#xff1a;精确到毫秒&#xff0c;代表特定的瞬间SimpleDateFor…

Redis缓存——Spring Cache入门学习

Spring Cache 介绍 Spring Cache 是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能。 Spring Cache 提供了一层抽象&#xff0c;底层可以切换不同的缓存实现&#xff0c;例如&#xff1a; EHCacheCaffeineR…

程序员世界破破烂烂,低代码总在缝缝补补

在经历了十几年的发展后&#xff0c;前端开发变得越来越复杂&#xff0c;门槛也越来越高&#xff0c;要使用当下流行的 UI 组件库&#xff0c;你必须懂 npm、webpack、react/vue&#xff0c;必须熟悉 ES6 语法&#xff0c;最好还了解状态管理&#xff0c;比如 Redux&#xff0c…

【IPv6】IPv6协议

一、IPv6数据报格式 这是与v4报头的对比 1.8bit的版本保留了&#xff0c;v4版本就是4&#xff0c;v6就是6。 2.v6去除了v4的首部长度字段&#xff0c;因为v6的首部长是固定的40字节。 3.服务类型&#xff08;Type of Service, ToS&#xff09;和通信类型&#xff08;Traffi…

Leetcode周赛374补题(3 / 3) - EA专场

不愧是EA的题&#xff0c;我最爱的模拟人生……好难&#xff0c;呜呜 目录 1、找出峰值 - 暴力枚举 2、需要添加的硬币的最小数量 - 思维 贪心 3、统计完全子字符串 - 滑窗 分组循环 1、找出峰值 - 暴力枚举 2951. 找出峰值 class Solution {public List<Integer> …

kubernetes监控GPA安装部署

本文在于指导如何对k8s的监控GPA(Grafana&#xff0c;prometheus以及alertmanager)进行安装部署。 1. 介绍 Prometheus 在真正部署Prometheus之前&#xff0c;应了解一下Prometheus的各个组件之间的关系及作用&#xff1a; 1&#xff09;MertricServer&#xff1a;是k8s集群…

Sentinel基础知识

Sentinel基础知识 资源 1、官方网址&#xff1a;https://sentinelguard.io/zh-cn/ 2、os-china: https://www.oschina.net/p/sentinel?hmsraladdin1e1 3、github: https://github.com/alibaba/Sentinel 一、软件简介 Sentinel 是面向分布式服务架构的高可用流量防护组件…

React 笔记 父子组件传值

React父子组件传值 react中的组件&#xff1a;解决HTML标签构建应用的不足。使用组件开发的好处&#xff1a;把公共的功能单独抽离成一个文件作为一个组件&#xff0c;哪里使用哪里引入。父子组件&#xff1a;组件的相互调用中&#xff0c;我们把调用者称为父组件&#xff0c;…

探究Logistic回归:用数学解释分类问题

文章目录 前言回归和分类Logistic回归线性回归Sigmoid函数把回归变成分类Logistic回归算法的数学推导Sigmoid函数与其他激活函数的比较 Logistic回归实例1. 数据预处理2. 模型定义3. 训练模型4. 结果可视化 结语 前言 当谈论当论及机器学习中的回归和分类问题时&#xff0c;很…

浅谈Python+requests+pytest接口自动化测试框架的搭建

框架的设计思路 首先要明确进行接口自动化需要的步骤&#xff0c;如下图所示&#xff1a; ​然后逐步拆解需要完成的工作&#xff1a; 1&#xff09;了解分析需求&#xff1a;了解接口要实现的功能 2&#xff09;数据准备&#xff1a;根据开发文档确定接口的基本情况&#x…

File.separator

File.separator代表系统默认文件目录分隔符&#xff0c;即我们所说的“斜线”。 在 windows 中 文件文件分隔符 用 ’ \ ’ 或者 ’ / ’ 都可以在 Linux 中&#xff0c;系统中分隔符为“/”&#xff0c;不识别 ’ \ ’ 例如&#xff1a; //在temp目录下建立一个test.txt文件…

Python + Appium框架原生代码实现App自动化测试

Step1&#xff1a;首先介绍下pythonappium的框架结构 如下截图所示 . (1)&#xff1a;apk目录主要放置待测app的apk资源&#xff1b; (2)&#xff1a;config目录主要放置配置文件信息&#xff0c;包含&#xff1a;数据库连接配置、UI自动化脚本中所需的页面元素信息及app启…

(C语言)判定一个字符串是否是另一个字符串的子串,若是则返回子串在主串中的位置。

要求&#xff1a; &#xff08;1&#xff09;在主函数中输入两个字符串&#xff0c;调用子函数cmpsubstr()判断&#xff0c;并在主函数输出结果。 &#xff08;2&#xff09;子函数的返回值为-1表示未找到&#xff0c;否则返回子串的位置&#xff08;起始下标&#xff09;。 …

Shell数组函数:数组(一)

一、数组简介&#xff1a; 变量&#xff1a;用一个固定的字符串&#xff0c;代替一个不固定字符串。数组&#xff1a;用一个固定的字符串&#xff0c;代替多个不固定字符串。 二、类型 普通数组&#xff1a;只能使用整数作为数组索引关联数组&#xff1a;可以使用字符串作为…

多表操作、其他字段和字段参数、django与ajax(回顾)

多表操作 1 基于对象的跨表查 子查询----》执行了两句sql&#xff0c;没有连表操作 2 基于双下滑线的连表查 一次查询&#xff0c;连表操作 3 正向和反向 放在ForeignKey,OneToOneField,ManyToManyField的-related_namebooks&#xff1a;双下滑线连表查询&#xff0c;反向…

Redis Hash数据类型

Redis Hash数据类型 几乎所有的主流编程语言都提供了哈希(hash)类型&#xff0c;它们的叫法可能是哈希、字典、关联数组、映射。在 Redis 中&#xff0c;哈希类型是指值本身又是一个键值对结构&#xff0c;形如key “key”&#xff0c;value {ffield1, value1 }, … {fieldN…

LoadBalancer将服务暴露到外部实现负载均衡purelb-layer2模式配置介绍

目录 一.purelb简介 1.简介 2.purelb的layer2工作模式特点 二.layer2的配置演示 1.首先准备ipvs和arp配置环境 2.purelb部署开始 &#xff08;1&#xff09;下载purelb-complete.yaml文件并应用 &#xff08;2&#xff09;查看该有的资源是否创建完成并运行 &#xff…

树莓派外接上显示器以后一直黑屏无画面显示

一般遇到这种情况都是因为没有强制支持热插拔引起的&#xff0c;先断电树莓派&#xff0c;确保显示器与树莓派连接正常&#xff0c;然后上电就可以正常显示了。 如果想要支持热插拔&#xff0c;可以修改配置文件。 sudo nano /boot/config.txt 修改如下配置 hdmi_force_hotpl…

GCN,GraphSAGE 到底在训练什么呢?

根据DGL 来做的&#xff0c;按照DGL 实现来讲述 1. GCN Cora 训练代码&#xff1a; import osos.environ["DGLBACKEND"] "pytorch" import dgl import dgl.data import torch import torch.nn as nn import torch.nn.functional as F from dgl.nn.pytorc…