当前位置:   article > 正文

《Rust权威指南》学习笔记之第9章 错误处理_rust语言use时出错

rust语言use时出错

两大类错误:

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

不可恢复错误与panic!

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

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

fn main() {
	panic!("crash and burn");
}
  • 1
  • 2
  • 3

panic!中产生回溯信息

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

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

RUST_BACKTRACE=1 cargo run
  • 1

可恢复错误与Result

enum Result<T, E> {
	OK(T),
	Err(E),
}
  • 1
  • 2
  • 3
  • 4
use std::fs::file;

fn main() {
	let f = File::open("hello.txt");
	//let f: u32 = File::open("hello.txt");	//报错查看类型
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
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);
		},
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

匹配不同错误

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),
		},
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
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);
		}
	});
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

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

use std::fs::file;

fn main() {
	let f = File::open("hello.txt").unwrap();
}
  • 1
  • 2
  • 3
  • 4
  • 5

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

use std::fs::file;

fn main() {
	let f = File::open("hello.txt").expect("Failed to open hello.txt");
}
  • 1
  • 2
  • 3
  • 4
  • 5

传播错误

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

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),
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

?放于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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
use std::io;
use std::fs;

fn read_username_from_file() -> Result<String, io::Error> {
	fs.read_to_sttring("hello.txt")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

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

fn main() -> Result<(), Box<dyn Error>> {
	let f = File::open("hello.txt")?;	
	Ok(())
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

要不要使用panic!

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

use std::net::IpAddr;

let home: IpAddr = "127.0.0.1".parse().unwrap();
  • 1
  • 2
  • 3

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

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) {

	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
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
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/702703
推荐阅读
相关标签
  

闽ICP备14008679号