《Rust权威指南》学习笔记之第9章 错误处理

news/2024/7/6 6:34:03

《Rust权威指南》学习笔记之第9章 错误处理

  • 不可恢复错误与panic!
  • panic!中产生回溯信息
  • 可恢复错误与Result
  • 匹配不同错误
  • 失败时触发panic的快捷方式:unwrap和expect
  • 传播错误
    • 传播错误的快捷方式:?运算符
    • ?运算符只能被用于返回Result的函数
    • 要不要使用panic!
    • 创建自定义类型进行有效性验证

两大类错误:

  • 可恢复错误
    文件未找到等,报告给用户并再次尝试。Result<T, E>
  • 不可恢复错误
    bug,尝试访问超过数组结尾的位置等。panic!

不可恢复错误与panic!

panic!宏执行时打印出一段错误提示信息,展开并清理当前的调用栈,然后退出程序。

panic中的栈展开与终止
panic发生时,程序会默认开始栈展开,反向遍历所有调用函数,并清理函数中的错误,需要二进制中存储许多额外信息。可以立即终止程序,而不进行任何清理,使用内存由操作系统回收。通过配置Carog.toml文件,减小二进制包。
[profile.release]
panic = ‘abort’

fn main() {
	panic!("crash and burn");
}

panic!中产生回溯信息

fn main() {
	let v = vec![1, 2, 3];
	v[99];	//缓冲区溢出(buffer overread)
}

获得回溯信息,必须启用调试符号 (debug symbol),cargo build或cargo run不附带–release标志。

RUST_BACKTRACE=1 cargo run

可恢复错误与Result

enum Result<T, E> {
	OK(T),
	Err(E),
}
use std::fs::file;

fn main() {
	let f = File::open("hello.txt");
	//let f: u32 = File::open("hello.txt");	//报错查看类型
}
use std::fs::file;

fn main() {
	let f = File::open("hello.txt");

	let f = match f {
		Ok(file) => file,
		Err(error) => {
			panic!("There was a problem opening the file: {:?}", error);
		},
	}
}

匹配不同错误

use std::fs::File;
use std::io::ErrorKind;

fn main() {
	let f = File::open("hello.txt");

	let f = match f {
		Ok(file) => file,
		Err(error) => match error.kind() {
			ErrorKind::NotFound => match File::create("hell.txt") {
				OK(fc) => fc,
				Err(e) => panic!("Tried to create file but there was a problem: {:?}", e),
			},
			other_error => panic!("There was a problem opening the file: {:?}", other_error),
		},
	}
}
use std::fs::File;
use std::io::ErrorKind;

fn main() {
	let f = File::open("hello.txt").map_err(|error| {
		if error.kind() == ErrorKind::NotFound {
			File::create("hell.txt").unwrap_or_else(|error| {
				panic!("Tried to create file but there was a problem: {:?}", error);
			});
		} else {
			panic!("There was a problem opening the file: {:?}", other_error);
		}
	});
}

失败时触发panic的快捷方式:unwrap和expect

unwrap方法,Result返回值是Ok时,返回Ok内值;Error时,调用panic。

use std::fs::file;

fn main() {
	let f = File::open("hello.txt").unwrap();
}

expect方法,在unwrap基础上指定panic!的错误提示信息。

use std::fs::file;

fn main() {
	let f = File::open("hello.txt").expect("Failed to open hello.txt");
}

传播错误

函数中包含可能会执行失败的调用时,可以将错误返回给调用者。

use std::io;
use std::io::Read;
use std::fs::File;

fn read_username_from_file() -> Result<String, io::Error> {
	let f = File::open("hello.txt");
	
	let mut f = match f {
		Ok(file) => file,
		Err(e) => return Err(e),
	}
	
	let mut s = String::new();

	match f.read_to_sttring(&mut s) {
		Ok(_) => Ok(s),
		Err(e) => Err(e),
	}
}

传播错误的快捷方式:?运算符

?放于Result后,Result值是Ok时,返回Ok中的值并继续执行程序;Err时,返回并退出程序。

?运算符接收的错误值会隐式地被from函数处理,定义于标准库的From trait中,用于错误类型间转换(传入错误类型转换为当前函数返回错误类型)。

use std::io;
use std::io::Read;
use std::fs::File;

fn read_username_from_file() -> Result<String, io::Error> {
	let mut f = File::open("hello.txt")?;	
	let mut s = String::new();
	f.read_to_sttring(&mut s)?;
	Ok(s)
}
use std::io;
use std::io::Read;
use std::fs::File;

fn read_username_from_file() -> Result<String, io::Error> {
	let mut s = String::new();
	File::open("hello.txt")?.read_to_sttring(&mut s)?;
	Ok(s)
}
use std::io;
use std::fs;

fn read_username_from_file() -> Result<String, io::Error> {
	fs.read_to_sttring("hello.txt")
}

?运算符只能被用于返回Result的函数

use std::error::Error;
use std::fs::File;

fn main() -> Result<(), Box<dyn Error>> {
	let f = File::open("hello.txt")?;	
	Ok(())
}

要不要使用panic!

不可恢复用panic!,定义可能失败的函数(失败可预期)优先考虑使用Result。
示例、原型和测试使用panic!。

use std::net::IpAddr;

let home: IpAddr = "127.0.0.1".parse().unwrap();

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

loop {

	let guess: i32 = match guess.trim().parse() {
		Ok(num) => num,
		Err(_) => continue,
	};

	if guess<1 || guess>100 {
		println!("The secret number will be between 1 and 100.");
		continue;
	}

	match guess.cmp(&secret_number) {

	}
}
pub struct Guess {
	value: i32,
}

impl Guess {
	pub fn new(value: i32) -> Guess {
		if value<1 || value>100 {
			panic!("Guess number must be between 1 and 100, got {}.", value);
		}
	}
	
	pub fn value(&self) -> i32 {	//读取接口(getter)
		self.value
	}
}

http://www.niftyadmin.cn/n/2037900.html

相关文章

P2018 消息传递

暴力贪心即可. 考虑从下往上计算. 对于一个根节点的所有子节点, 明显我们应该优先告诉耗时长的子节点. 于是贪心. 假设已经知道了所有子节点的最少花费时间. 我们将其从小到大排序, 那么最后一个应该最先告诉.这可以通过交换法证明. 当前节点的最小花费也就可以构造出来了. #in…

bzoj 1510 [POI2006]Kra-The Disks——思路

题目&#xff1a;https://www.lydsy.com/JudgeOnline/problem.php?id1510 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N3e55,INF1e95; int n,m,h[N],r,p0; int rdn() {int ret0;boo…

C/C++数学运算

C/C数学运算 - * /和数值组成的字符串表达式解析 - * / % ^ ()和数学函数组成的字符串表达式解析最终版字符串计算 - * /和数值组成的字符串表达式解析 #include <iostream> #include <stack> using namespace std;enum TOKEN_TYPE {OPERATOR, NUMBER };//去除exp…

转Jmeter报告优化之New XSL stylesheet

Jmeter默认的报告展示的信息比较少&#xff0c;如果出错了&#xff0c;不是很方便定位问题。由Jmeter默认报告优化这篇文章可知&#xff0c;其实由.jtl格式转换为.html格式的报告过程中&#xff0c;style文件起了很关键的作用。下面介绍另一种style文件的使用方法&#xff1a; …

计算机网络概述 传输层 TCP拥塞控制

TCP拥塞控制 计算机网络中的带宽、交换结点中的缓存和处理机等&#xff0c;都是网络的资源。在某段时间&#xff0c;若对网络中某一资源的需求超过了该资源所能提供的可用部分&#xff0c;网络的性能就会变坏。这种情况就叫做拥塞。 拥塞控制就是防止过多的数据注入网络中&…

PHP登录怎么写安全,PHP登录安全理念

我有一个系统登录用户并验证他们在页面上登录的想法 .我意识到那里有很多系统&#xff0c;但我主要是好奇&#xff0c;如果我的想法是好的 . 我一直认为是重要的做法(如密码加密等) . 我真的使用了应用程序安全性&#xff0c;希望得到一些反馈 .当用户登录时&#xff0c;他们的…

基于OpenSSL的HTTPS通信C++实现

HTTPS是以安全为目标的HTTP通道&#xff0c;简单讲是HTTP的安全版。即HTTP下加入SSL层&#xff0c;HTTPS的安全基础是SSL&#xff0c;因此加密的详细内容就需要SSL。Nebula是一个为开发者提供一个快速开发高并发网络服务程序或搭建高并发分布式服务集群的高性能事件驱动网络框架…

php 编译redis ubuntu,Ubuntu安装php的redis扩展并配置PHP5.6

一、安装Redis1.下载Redis-4.0.8.tar.gz# wget http://download.redis.io/releases/redis-4.0.8.tar.gz2.解压&#xff1a;# tar zxvf redis-4.0.8.tar.gz3.进入redis-4.0.8目录# cd redis-4.0.84.编译(需要root权限)# make && make install5.配置文件&#xff0c;使服…