错误处理
在Rust中没有“异常”
错误分为可恢复和不可恢复
不可恢复的错误:panic!()
两种导致panic的方式:
- 代码中的某些行为导致panic
- 显式的调用panic!()宏
默认情况下:
panic后,会打印失败信息,展开Stack,清理Stack
Panic后的响应
设置立即终止,需要在Cargo.toml中加入:
1 2
| [profile.release] panic = "abort"
|
使用Result处理可恢复错误
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| use std::{fs::File, io::ErrorKind};
fn main() { let file_fp = File::open("hello.txt");
let file_fp = match File::open("hello.txt") { Ok(file) => file, Err(error) => match error.kind() { ErrorKind::NotFound => match File::create("hello.txt") { Ok(fc) => fc, Err(_) => panic!("Can't create file") }, _ => panic!("Error") } };
let file_fp = File::open("hello1.txt").unwrap(); let file_fp = File::open("hello2.txt").expect("Can't open");
}use std::{fs::File, io::ErrorKind};
fn main() { let file_fp = File::open("hello.txt");
let file_fp = match File::open("hello.txt") { Ok(file) => file, Err(error) => match error.kind() { ErrorKind::NotFound => match File::create("hello.txt") { Ok(fc) => fc, Err(_) => panic!("Can't create file") }, _ => panic!("Error") } };
let file_fp = File::open("hello1.txt").unwrap(); let file_fp = File::open("hello2.txt").expect("Can't open");
}
|
传播错误
将错误返回,由调用该函数的代码来决定如何处理错误.
? 运算符(operator)
使用? 运算符时
- 如果操作成功,它会解包Ok并继续执行下一行代码
- 如果操作失败,它会立即返回Err,并将错误传播给调用者
使用? 运算符可以避免大量的match或if let语句,使代码更简洁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| use std::fs::File; use std::io; use std::io::{Error, Read}; use std::num::ParseIntError;
#[derive(Debug)] pub enum MyError { Io(Error), ParseInt(ParseIntError), Other(String) }
impl From<Error> for MyError { fn from(value: Error) -> Self { MyError::Io(value) } }
impl From<ParseIntError> for MyError { fn from(value: ParseIntError) -> Self { MyError::ParseInt(value) } }
fn read_username_from_file_test() -> Result<String, MyError> { let mut username = String::new(); File::open("hello.txt")?.read_to_string(&mut username)?; let num :i32= "55".parse()?; Ok(username) }
fn read_username_from_file() -> Result<String, io::Error> { let mut username = String::new(); File::open("hello.txt")?.read_to_string(&mut username)?; Ok(username)
}
fn main() {
}
|
泛型
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| use std::char::UNICODE_VERSION;
struct Point<T, U> { x: T, y: U }
fn fun() { let integer = Point { x: 5, y: 10 }; let float = Point { x: 1.0, y: 1 }; }
impl<T, U> Point<T, U> { fn x(&self) -> &T { &self.x } }
fn main() { let number_list = vec![43, 56, 666, 1145, 33]; let result = largest(&number_list); println!("{result}"); let char_list = vec!['c', 'f', 'w', 'a', 'k']; let result = largest(&char_list); println!("{result}"); }
fn largest<T: PartialOrd>(list: &[T]) -> &T { let mut largest = &list[0]; for item in list { if item > largest { largest = item; } } largest }
|
Trait
定义Trait
类型的行为:可以在该类型上调用的方法
Trait定义:将不同的方法签名组成一个方法签名,由此定义一套共享的行为。
Trait的实现规则
只要trait或类型其中之一属于当前crate,就可以实现该trait
合法示例:
- 在本地类型Tweet上实现标准库的Display(trait)
- 在标准库的Vec上实现本地的Summary(trait)
非法示例:
- 不能在Vec上实现Display(trait)(因为两者都来自标准库)
致性和孤儿规则:
孤儿规则要求trait或类型必须属于当前crate,防止冲突实现
例:
lib.rs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| pub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String }
pub struct Tweet { pub username: String, pub content: String, pub reply: bool, pub retweet: bool }
pub trait Summary { fn summarize(&self) -> String { format!("(Read more from {}...)", self.summarize_author()) }
fn summarize_author(&self) -> String; }
impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}, by {} ({})", self.headline, self.author, self.location) }
fn summarize_author(&self) -> String { format!("@{}", self.author) } }
impl Summary for Tweet { fn summarize(&self) -> String { format!("{}: {}", self.username, self.content) }
fn summarize_author(&self) -> String { format!("@{}", self.username) } }
pub fn notify<T: Summary>(item: &T) { println!("{}", item.summarize()); }
|
main.rs
1 2 3 4 5 6 7 8 9 10 11 12 13
| use planb::{Summary, Tweet};
fn main() { let tweet = Tweet { username: String::from("A"), content: String::from("BBBB"), reply: false, retweet: false };
println!("{}", tweet.summarize()); }
|