Rust语言从入门到精通系列 - 避免Panic程序崩溃
在Rust语言中,当发生一些不可修复的错误时,程序会崩溃并停止运行。这种崩溃被称为”panic”,其中包含了出现问题的文件名和行号等信息。
Panic是一种紧急情况,并且它们应该尽可能地被避免。尽管它们可能是不可避免的,但是在编写代码时我们应该尝试处理尽可能多的错误。
如何使用Panic?
在Rust中,可以使用panic!
宏来引发panic。此时,程序将停止运行并打印出错误信息,这些信息通常包括出错的文件名称和行号等信息。同时,也可以使用环境变量来获取更多的栈跟踪信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Animal {
name: String,
age: u8,
}
impl Animal {
fn new(name: String, age: u8) -> Animal {
if age < 1 {
panic!("Age cannot be less than 1.");
}
Animal { name, age }
}
}
fn main() {
let animal = Animal::new(String::from("Tom"), 0);
println!("The animal's name is {} and age is {}.", animal.name, animal.age);
}
在上述的示例代码中,我们定义了一个结构体Animal
,并为它添加了一个函数new
,该函数接受一个名称和一定年龄的参数。接着在new
函数中,我们加入了一行代码,以检查年龄是否小于1,如果小于1,则触发panic。最后在main
函数中,我们创建了一个名为animal
的实例,并输出其名称和年龄。但是由于我们传递的年龄小于1,所以当运行到这里时,程序就会发生panic。
当运行这段代码时,输出如下信息:
thread 'main' panicked at 'Age cannot be less than 1.', src/main.rs:9:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
这个信息告诉我们,在执行new
函数时,程序崩溃,并指出出错的源代码文件和行号。同时,它还为我们建议了一个环境变量,以获取更详细的栈跟踪信息。
如何避免Panic?
对于大多数情况而言,应该尽可能少使用panic。在开始一个新的项目时,首先要考虑的是如何处理错误而不是如何处理成功的情况。
Result类型
在Rust中,可以使用Result
类型来避免panic。Result
类型包括两个枚举值:Ok
和Err
。当一个函数返回Result
类型时,它要么返回一个包含成功结果数据的Ok
,要么返回一个包含错误信息的Err
。这样,调用者就可以选择如何处理错误。
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
struct Animal {
name: String,
age: u8,
}
impl Animal {
fn new(name: String, age: u8) -> Result<Animal, String> {
if age < 1 {
return Err(String::from("Age cannot be less than 1."));
}
Ok(Animal { name, age })
}
}
fn main() {
let animal_result = Animal::new(String::from("Tom"), 0);
match animal_result {
Ok(animal) => {
println!("The animal's name is {} and age is {}.", animal.name, animal.age);
}
Err(error) => {
println!("{}", error);
}
}
}
在上面的代码中,我们对new
函数进行了修改,使其返回Result
类型。如果年龄小于1,则返回一个包含错误信息的Err
。如果年龄大于等于1,则返回一个包含动物实例的Ok
。
在main
函数中,我们创建了一个名为animal_result
的变量,并将其设置为调用Animal
结构体中的new
函数的返回值。我们使用match
表达式来处理animal_result
,如果成功,则输出动物实例的名称和年龄,否则则输出错误信息。
unwrap和expect方法
在Rust中的Result
类型中,还有两个用于从Ok
值中提取值的方法:unwrap
和expect
。这两个方法都可以用于快速编写测试代码,并且在这种情况下,panic可能是可以接受的。但是在实际生产代码中,应该避免使用这两个方法,因为它们会利用panic而不是正确处理错误。
1
2
3
4
5
6
7
fn main() {
let animal = Animal::new(String::from("Tom"), 1).unwrap();
println!("The animal's name is {} and age is {}.", animal.name, animal.age);
let animal = Animal::new(String::from("Tom"), 0).expect("Failed to create animal instance.");
println!("The animal's name is {} and age is {}.", animal.name, animal.age);
}
在上述示例中,我们在创建animal
实例时使用了unwrap
和expect
方法。在使用unwrap
方法时,如果返回值是Ok
,则返回Ok
类型的值,否则触发panic。而使用expect
方法时,同样是如果返回值是Ok
,则返回Ok
类型的值,并输出指定的错误信息,否则触发panic。
总结
Rust语言的panic是一种程序崩溃的情况,应该尽可能地避免它的发生。为了避免panic,我们应该尽量使用Result
类型,并且在返回错误时返回一个包含错误信息的Err
。在测试代码中,可以使用unwrap
和expect
方法,但是在实际生产代码中应该避免它们的使用。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 TinyZ Zzh (包含链接: https://tinyzzh.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。 如有任何疑问,请 与我联系 (tinyzzh815@gmail.com) 。
评论