sui_rust/ch02/
s7_error_handle.rs

1//! 第二章:Rust核心概念
2//! 2.6 错误处理
3//!
4//! 1. 类型系统保证函数契约
5//! 2. 断言用于防御
6//! 3. Option<T> 消除空指针失败
7//! 4. Result<T, E> 传播错误
8//! 5. Panic 恐慌崩溃
9//!
10
11/**
12
13
14# 消除失败
15
161. 类型系统保证函数契约
17
18```rust
19fn sum(a: i32, b: i32) -> i32 {
20    a + b
21}
22fn main() {
23    sum(1u32, 2u32); // 违反契约,报错
24}
25```
26
272. 断言用于防御
28
29```rust
30
31fn extend_vec(v: &mut Vec<i32>, i: i32) {
32    assert!(v.len() == 5);
33    v.push(i);
34}
35fn main() {
36    let mut vec = vec![1, 2, 3];
37    extend_vec(&mut vec, 4);
38    extend_vec(&mut vec, 5);
39    extend_vec(&mut vec, 6); // panic!
40}
41```
42*/
43pub fn elim_failure() {
44    println!("Eliminate Failure!");
45}
46
47/**
48
49# 分层错误处理
50
51错误处理:顾名思义,处理错误。既然要处理错误,那肯定是指开发者可以处理的情况。
52
53-  Option: 「有」与「无」
54-  Result:「对」与「错」
55
56### Option
57
58```rust
59fn get_shortest(names: Vec<&str>) -> Option<&str> {
60    if names.len() > 0 {
61        let mut shortest = names[0];
62        for name in names.iter() {
63            if name.len() < shortest.len() {
64                shortest = *name;
65            }
66        }
67        Some(shortest)
68   } else {
69       None
70   }
71}
72fn show_shortest(names: Vec<&str>) -> &str {
73   match get_shortest(names) {
74       Some(shortest) => shortest,
75       None             => "Not Found",
76   }
77}
78fn main(){
79   assert_eq!(show_shortest(vec!["Uku", "Felipe"]), "Uku");
80   assert_eq!(show_shortest(Vec::new()), "Not Found");
81}
82```
83
84使用 Match 在 「盒内」处理 Option
85
86```rust
87fn get_shortest_length(names: Vec<&str>) -> Option<usize> {
88    match get_shortest(names) {
89        Some(shortest) => Some(shortest.len()),
90        None             => None,
91    }
92}
93fn main(){
94    assert_eq!(get_shortest_length(vec!["Uku","Felipe"]),Some(3));
95    assert_eq!(get_shortest_length(Vec::new()), None);
96}
97```
98
99使用标准库内建组合子处理:
100
101```rust
102fn double(value: f64) -> f64 {
103    value * 2.
104}
105fn square(value: f64) -> f64 {
106    value.powi(2 as i32)
107}
108fn inverse(value: f64) -> f64 {
109    value * -1.
110}
111fn log(value: f64) -> Option<f64> {
112   match value.log2() {
113       x if x.is_normal() => Some(x),
114       _                      => None
115   }
116}
117fn sqrt(value: f64) -> Option<f64> {
118   match value.sqrt() {
119       x if x.is_normal() => Some(x),
120       _                      => None
121   }
122}
123fn main () {
124   let number: f64 = 20.;
125   let result = Option::from(number)
126       .map(inverse).map(double).map(inverse)
127       .and_then(log).map(square).and_then(sqrt);
128   match result {
129       Some(x) => println!("Result was {}.", x),
130       None    => println!("This failed.")
131   }
132}
133```
134
135
136### Result
137
138- Error trait:[https://doc.rust-lang.org/stable/std/error/trait.Error.html](https://doc.rust-lang.org/stable/std/error/trait.Error.html)
139- Result Error Handle : [read-sum crate]
140- `?` and [std::ops::Try](https://doc.rust-lang.org/stable/std/ops/trait.Try.html)
141
142
143
144
145```rust
146use std::num::ParseIntError;
147// fn square(number_str: &str) -> Result<i32, ParseIntError>
148// {
149//    number_str.parse::<i32>().map(|n| n.pow(2))
150// }
151type ParseResult<T> = Result<T, ParseIntError>;
152fn square(number_str: &str) -> ParseResult<i32>
153{
154    number_str.parse::<i32>().map(|n| n.pow(2))
155}
156fn main() {
157    match square("10") {
158        Ok(n) => assert_eq!(n, 100),
159        Err(err) => println!("Error: {:?}", err),
160    }
161}
162```
163
164
165*/
166pub fn error_handle() {
167    println!("Error Handle!")
168}
169
170/**
171
172### panic 的两种类型:
173
174- Unwinding(栈展开)。
175- Aborting(中止)。
176
177Unwinding 可以使应用程序线程以相对干净的方式关闭。
178回收所有分配的系统资源,正确删除所有应用程序对象,依此类推。
179此外,恐慌停止在有问题的线程的边界,而不是杀死整个应用程序过程。
180所有这一切意味着,如果所有对象都具有明智的析构函数,则尽管有困难,但仍可以从紧急情况中恢复应用程序。
181
182如果你应用程序是为此目的而设计的,则可以检测到线程紧急情况并重新启动有问题的线程,希望该操作能够正确恢复。
183在无法关闭应用程序的情况下,例如在关键系统中,类似于Erlang的容错方法可能是有意义的。
184
185对于Aborting,不存在应用程序恢复的可能性。一旦某些代码中止,应用程序进程将立即终止,这意味着要实现容错功能,就需要进行更加复杂的多进程设计。
186另外,由于未运行资源析构函数,因此整个系统可能处于不一致状态,这意味着重新启动应用程序可能非常不容易。
187
188总而言之,仅应在确实不关心应用程序立即崩溃并可能破坏在崩溃过程中操作的任何硬件/操作系统状态的情况下启用Aborting恐慌。
189
190需要了解一个事实,Rust 目前对 OOM(out of memory)对处理是直接 Aborting ,无论你如何设置Panic类型。
191
192### 恐慌安全:
193
194[Rust Magazine #01 security](https://rustmagazine.github.io/rust_magazine_2021/chapter_1/rust_security_part1.html)
195- catch_unwind
196
197
198```rust
199
200use std::panic;
201fn sum(a: i32, b: i32) -> i32{
202    a + b
203}
204fn main() {
205    let result = panic::catch_unwind(|| { println!("hello!"); });
206    assert!(result.is_ok());
207    let result = panic::catch_unwind(|| { panic!("oh no!"); });
208    assert!(result.is_err());
209   println!("{}", sum(1, 2));
210}
211```
212
213使用 set_hook
214
215```rust
216use std::panic;
217fn sum(a: i32, b: i32) -> i32{
218    a + b
219}
220fn main() {
221    let result = panic::catch_unwind(|| { println!("hello!"); });
222    assert!(result.is_ok());
223    panic::set_hook(Box::new(|panic_info| {
224        if let Some(location) = panic_info.location() {
225            println!("panic occurred '{}' at {}",
226                location.file(), location.line()
227            );
228       } else {
229            println!("can't get location information...");
230       }
231   }));
232   let result = panic::catch_unwind(|| { panic!("oh no!"); });
233   assert!(result.is_err());
234   println!("{}", sum(1, 2));
235}
236```
237
238
239*/
240pub fn panic_cant_handle() {
241    println!("Panic Can't Handle")
242}