错误处理
1.用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:ToolsdevToolsvscodecoderustworld_hello> cargo run
Compiling world_hello v0.1.0 (C:ToolsdevToolsvscodecoderustworld_hello)
Finished dev [unoptimized + debuginfo] target(s) in 0.25s
Running `targetdebugworld_hello.exe`
thread 'main' panicked at srcmain.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: `targetdebugworld_hello.exe` (exit code: 101)
2.当设置RUST_BACKTRACE环境变量时panic!调用所生成的backtrace信息
>$env:RUST_BACKTRACE=1; cargo run
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 srcmain.rs:6:21:
Problem opening the file: Os { code: 2, kind: NotFound, message: "系统找不到指定的文件。" }
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/librarystdsrcpanicking.rs:597
1: core::panicking::panic_fmt
at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/librarycoresrcpanicking.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
use std::fs::File;
fn main() {
let greeting_file_result = File::open("../Cargo.lock").unwrap();
}
2.expect
use std::fs::File;
fn main() {
let greeting_file_result = File::open("../Cargo.lock").expect("Cargo.lock should be included in this project");
}
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函数中使用?的代码不能编译
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错误处理指导原则
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
}
}
原文地址:https://blog.csdn.net/qq_39656068/article/details/134715628
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_25602.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。