【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据
【跟小嘉学 Rust 编程】六、枚举和模式匹配
【跟小嘉学 Rust 编程】七、使用包(Packages)、单元包(Crates)和模块(Module)来管理项目
【跟小嘉学 Rust 编程】八、常见的集合
【跟小嘉学 Rust 编程】九、错误处理(Error Handling)
Rust的可靠性源自于错误处理,大部分情况下,在编译时提示错误并处理。Rust 将错误分为两大类:不可恢复的和可恢复的错误。对于可恢复的错误,例如未找到文件,很能只向用户报告问题并重试操作。不可恢复的错误总是bug的症状,比如试图访问超过数组末尾的位置,因此我们希望立即停止程序。
大多数语言不区分这两种错误,并以相同的方式处理这两种错误,使用异常等机制。Rust 之中没有异常。
主要教材参考 《The Rust Programming Language》
对于panic 的情况
如果想让二进制文件更小,可以把设置从展开(unwinding)改为中止(Cargo.toml)
[profile.release]
panic = 'abort'
panic
宏使用 panic!
宏可以抛出一个 panic
fn main() {
panic!("crash and burn!");
}
运行结果
cargo run
Compiling my-project v0.1.0 (~/Desktop/code/rust_code/my-project)
Finished dev [unoptimized + debuginfo] target(s) in 0.86s
Running `target/debug/my-project`
thread 'main' panicked at 'crash and burn!', src/main.rs:5:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
索引越界例子:
fn main() {
let v = vec![1,2,3];
v[99];
}
运行结果:
Compiling my-project v0.1.0 (~/code/rust_code/my-project)
Finished dev [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/my-project`
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:6:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
从错误信息可以看出设置环境变量 RUST_BACKTRACE=1
就可以显示回溯信息;设置成 RUST_BACKTRACE=full
可以看到更多的详细信息。
大部分错误其实并没有严重到无法恢复需要停止执行的地步,因此可以通过捕获 Result 枚举类型来从错误中恢复。
enum Result<T, E> { // T, E 都是泛型参数
Ok(T),
Err(E),
}
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let _f = match f {
Ok(file) => file,
Err(error) =>{
panic!("Error open 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("hello.txt") {
Ok(fc)=>fc,
Err(e)=> panic!("文件创建失败:{:?}", e)
}
other_error => panic!("打开文件失败:{:?}", other_error),
}
};
}
使用闭包可以让代码更加简洁,可以省去很多 match 的嵌套
use core::panic;
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("hello.txt").unwrap_or_else(|error|{
if error.kind() == ErrorKind::NotFound {
File::create("hello.txt").unwrap_or_else(|error|{
panic!("文件创建失败:{:?}", error);
})
}else{
panic!("打开文件失败:{:?}", error);
}
});
}
match 表达式的一个快捷的写法
let f = File::open("hello.txt").unwrap();
expect 和 unwrap 类似,unwrap不能指定 错误信息,而 expect 可以指定错误信息。
let f = File::open("hello.txt").expect("打开文件失败");
有些人喜欢原地处理,有些人需要将错误传递给上层调用处进行处理。 rust 提供?来进行错哦污传播哦。
#![allow(unused)]
fn main() {
use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
let res = read_username_from_file();
dbg!(&res);
}
并不是所有的错误都能被隐式的被 Trait std::convert::From
上的 from 函数转换。用于针对不同错误原因,返回同一种错误类型:只要每个错误类型都实现了转换为返回的错误类型的from函数。
?
问号运算符只能用于返回值是 Result 或者Option,或者实现了 Try的类型。
默认的main 函数返回值是 ()
类型,我们也可以让 main 函数返回 Result 类型。
use std::fs::File;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>>{
let f = File::open("hello.txt")?;
Ok(())
}
在定义一个可能失败的函数,优先考虑返回Result,否则返回panic。
有时候你比编译器掌握更多的信息,你可以确定 Result 就是OK:unwrap
use std::net::IpAddr;
fn main() {
let home: IpAddr= "127.0.0.1".parse().unwrap();
}
当代码最终可能处于损坏状态(Bad State),最好用 panic!。
损坏状态(Bad State):某些假设、保证、约定或不可变性被打破。
以上就是今天要讲的内容