<style>
.textleft {
text-align:left;
}
.reveal, .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {
font-family:Arial, Microsoft JhengHei;}
.reveal .progress {
height: 14px !important;
}
.progress span {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAIAAAAs6UAAAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUNCQzIyREQ0QjdEMTFFMzlEMDM4Qzc3MEY0NzdGMDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUNCQzIyREU0QjdEMTFFMzlEMDM4Qzc3MEY0NzdGMDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQ0JDMjJEQjRCN0QxMUUzOUQwMzhDNzcwRjQ3N0YwOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQ0JDMjJEQzRCN0QxMUUzOUQwMzhDNzcwRjQ3N0YwOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PovDFgYAAAAmSURBVHjaYvjPwMAAxjMZmBhA9H8INv4P4TPM/A+m04zBNECAAQBCWQv9SUQpVgAAAABJRU5ErkJggg==) repeat-x !important;
}
.progress span:after, .progress span.nyancat {
content: "";
background: url(data:image/gif;base64,R0lGODlhIgAVAKIHAL3/9/+Zmf8zmf/MmZmZmf+Z/wAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpDMkJBNjY5RTU1NEJFMzExOUM4QUM2MDAwNDQzRERBQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCREIzOEIzMzRCN0IxMUUzODhEQjgwOTYzMTgyNTE0QiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCREIzOEIzMjRCN0IxMUUzODhEQjgwOTYzMTgyNTE0QiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkM1QkE2NjlFNTU0QkUzMTE5QzhBQzYwMDA0NDNEREFDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMyQkE2NjlFNTU0QkUzMTE5QzhBQzYwMDA0NDNEREFDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8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) ;
width: 34px !important;
height: 21px !important;
border: none !important;
float: right;
margin-top: -7px;
margin-right: -10px;
}
.my-icon-css {
width: 100%;
height: 200px;
background-position:center;
background-repeat: no-repeat;
background-image:url('https://mir-s3-cdn-cf.behance.net/project_modules/disp/fe36cc42774743.57ee5f329fae6.gif');
}
</style>
<!-- .slide: data-transition="slide" -->
# <h2>ch9. Error Handling</h2>
<div class="my-icon-css"></div>
@Kais(VagrantPi)
###### tags: `Rust`, `簡報`, `Rust 讀書會`
---
<!-- .slide: data-transition="convex" -->
## Agenda
- Unrecoverable Errors with panic!
- Recoverable Errors with Result
- To panic! or Not To panic!
---
<!-- .slide: data-transition="convex" -->
## Unrecoverable Errors with panic!
----
<!-- .slide: data-transition="convex" -->
### Rust 中的錯誤
- 可恢復錯誤(recoverable)
<!--可恢復錯誤通常代跟 user 報錯或是 retry 是合理的情况,比如上傳檔案未找到檔案-->
- 不可恢復錯誤(unrecoverable)
<!--不可恢復錯誤通常是 bug 的同義詞,比如嘗試讀取陣列範圍外的位置-->
----
<!-- .slide: data-transition="convex" -->
### Panic 又可分為兩種模式:
- 展開(unwinding)預設值
<!--Rust 會回朔並清理它遇到的每一个函式用過的資源(變數啥的)-->
- 終止(abort)
<!--不會清理數據就直接退出,這些使用的内存需要由操作系统来清理,build 出來的 binery 會比較小-->
*Cargo.toml 的 [profile] 部分增加 panic = ‘abort’*
----
<!-- .slide: data-transition="convex" -->
```javascript=
fn main() {
panic!("crash and burn");
}
```
```
$ cargo run
Compiling rust v0.1.0 (file:///Users/kais.lin/rust)
Finished dev [unoptimized + debuginfo] target(s) in 3.42 secs
Running `target/debug/rust`
thread 'main' panicked at 'crash and burn', main.rs:2:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
```
<!--不過在其他情況下,panic 會發生在呼叫的函數中,此時錯誤訊息會是指向該函式,而不是我們呼叫的那一行,這時可以使用 backtrace 來尋找-->
----
<!-- .slide: data-transition="convex" -->
### 使用 panic! 的 backtrace
```javascript=
fn main() {
let v = vec![1, 2, 3];
v[99];
}
```
```
$ cargo run
Compiling rust v0.1.0 (file:///Users/kais.lin/rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.34 secs
Running `target/debug/rust`
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /Users/travis/build/rust-lang/rust/src/libcore/slice/mod.rs:865:10
note: Run with `RUST_BACKTRACE=1` for a backtrace.
```
----
<!-- .slide: data-transition="convex" -->
```
$ RUST_BACKTRACE=1 cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/rust`
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /Users/travis/build/rust-lang/rust/src/libcore/slice/mod.rs:865:10
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
1: std::sys_common::backtrace::print
at libstd/sys_common/backtrace.rs:71
at libstd/sys_common/backtrace.rs:59
2: std::panicking::default_hook::{{closure}}
at libstd/panicking.rs:207
3: std::panicking::default_hook
at libstd/panicking.rs:223
4: std::panicking::begin_panic
at libstd/panicking.rs:402
5: std::panicking::try::do_call
at libstd/panicking.rs:349
6: std::panicking::try::do_call
at libstd/panicking.rs:325
7: core::ptr::drop_in_place
at libcore/panicking.rs:72
8: core::ptr::drop_in_place
at libcore/panicking.rs:58
9: <usize as core::slice::SliceIndex<[T]>>::index
at /Users/travis/build/rust-lang/rust/src/libcore/slice/mod.rs:865
10: core::slice::<impl core::ops::index::Index<I> for [T]>::index
at /Users/travis/build/rust-lang/rust/src/libcore/slice/mod.rs:767
11: <alloc::vec::Vec<T> as core::ops::index::Index<I>>::index
at /Users/travis/build/rust-lang/rust/src/liballoc/vec.rs:1648
12: rust::main
at ./main.rs:4
13: std::rt::lang_start::{{closure}}
at /Users/travis/build/rust-lang/rust/src/libstd/rt.rs:74
14: std::panicking::try::do_call
at libstd/rt.rs:59
at libstd/panicking.rs:306
15: panic_unwind::dwarf::eh::read_encoded_pointer
at libpanic_unwind/lib.rs:102
16: <std::io::Write::write_fmt::Adaptor<'a, T> as core::fmt::Write>::write_str
at libstd/panicking.rs:285
at libstd/panic.rs:361
at libstd/rt.rs:58
17: std::rt::lang_start
at /Users/travis/build/rust-lang/rust/src/libstd/rt.rs:74
18: rust::main
```
```
12: rust::main
at ./main.rs:4
```
---
<!-- .slide: data-transition="convex" -->
## Recoverable Errors with Result
----
<!-- .slide: data-transition="convex" -->
### 面對它
使用 `Result` 類型來處理潛在錯誤
```javascript
enum Result<T, E> {
Ok(T),
Err(E),
}
```
如何知道某某函數會回傳 `Rusult` 呢?除文件之外,書中也提到了另一個方法
----
<!-- .slide: data-transition="convex" -->
### 執行它
```javascript=
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
}
```
```
error[E0308]: mismatched types
--> src/main.rs:4:18
|
4 | let f: u32 = File::open("hello.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^ expected u32, found enum
`std::result::Result`
|
= note: expected type `u32`
found type `std::result::Result<std::fs::File, std::io::Error>`
```
----
<!-- .slide: data-transition="convex" -->
### 處理它
```javascript=
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => {
panic!("There was a problem opening the file: {:?}", error)
},
};
}
```
----
<!-- .slide: data-transition="convex" -->
```javascript=
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(ref error) if error.kind() == ErrorKind::NotFound => {
match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => {
panic!(
"Tried to create file but there was a problem: {:?}",
e
)
},
}
},
Err(error) => {
panic!(
"There was a problem opening the file: {:?}",
error
)
},
};
}
```
if error.kind() == ErrorKind::NotFound 被稱為 `match guard`,用來更完善 match 的而外條件判斷
----
<!-- .slide: data-transition="convex" -->
### 失敗時 panic 的簡寫:unwrap
```javascript=
use std::fs::File;
fn main() {
let f = File::open("hello.txt").unwrap();
}
```
```
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error {
repr: Os { code: 2, message: "No such file or directory" } }',
src/libcore/result.rs:906:4
```
----
<!-- .slide: data-transition="convex" -->
### 失敗時 panic 的簡寫:expect
```javascript=
use std::fs::File;
fn main() {
let f = File::open("hello.txt").expect("Failed to open hello.txt");
}
```
```
thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code:
2, message: "No such file or directory" } }', src/libcore/result.rs:906:4
```
----
<!-- .slide: data-transition="convex" -->
### 傳播(propagating)錯誤
簡單說就是 function 會回傳 error,這樣可以讓呼叫他的地方能夠判斷要不要做錯誤處裡
```javascript=
use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
```
----
<!-- .slide: data-transition="convex" -->
### 傳播錯誤的簡寫: ?
```javascript=
use std::io;
use std::io::Read;
use std::fs::File;
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)
}
```
----
<!-- .slide: data-transition="convex" -->
### 與 match 的差別
原文理解不能,以下是我個人理解,請大大們勘誤
`?` 會將錯誤值丟給 from 函數(定義於 From trait 中),可以將 Result 回傳的錯誤型別,轉換成該 fn 回傳的錯誤型別
----
<!-- .slide: data-transition="convex" -->
```javascript=
use std::io::{self, Read};
use std::num;
enum CliError {
IoError(io::Error),
ParseError(num::ParseIntError),
}
impl From<io::Error> for CliError {
fn from(error: io::Error) -> Self {
CliError::IoError(error)
}
}
impl From<num::ParseIntError> for CliError {
fn from(error: num::ParseIntError) -> Self {
CliError::ParseError(error)
}
}
fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
let mut file = std::fs::File::open("test")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let num: i32 = contents.trim().parse()?;
Ok(num)
}
```
> [trait.From](https://doc.rust-lang.org/std/convert/trait.From.html)
----
<!-- .slide: data-transition="convex" -->
### ? 只能被用于返回 Result 的函数
```javascript=
use std::fs::File;
fn main() {
let f = File::open("hello.txt")?;
}
```
```
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
--> src/main.rs:4:13
|
4 | let f = File::open("hello.txt")?;
| ------------------------
| |
| the `?` operator can only be used in a function that returns
`Result` (or another type that implements `std::ops::Try`)
| in this macro invocation
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
```
---
<!-- .slide: data-transition="convex" -->
## To panic! or Not To panic!
----
<!-- .slide: data-transition="convex" -->
### Examples, Prototype Code, and Tests
有時候只是要快速的驗證或者是 demo,可以先 unwrap 之類的方法,未來再來實現這部廢的錯誤處理
----
<!-- .slide: data-transition="convex" -->
### 當你比編譯器知道更多情況
```javascript=
use std::net::IpAddr;
let home: IpAddr = "127.0.0.1".parse().unwrap();
```
即便是寫死的,而且確定是可分析的 ip,編譯器仍會覺得還是可能會出現 Err 因此要我們處理 Result,這邊種情況下使用 unwrap 是合適的
----
<!-- .slide: data-transition="convex" -->
### 當輸入值錯誤時
預期外的傳入值,可能導致存取非當前資料的記憶體空間,而出現安全性問題
不過透過 Rust 的 type system 就會為你做很多檢查了(EX: u32 接到的值不會有負的)
<!--程式在對值進行操作時,應該先驗證其為有效值,否則就 panic!,主要是因為安全原因,嘗試操作無效數據可能會暴露程式漏洞,嘗試訪問不屬於當前數據的記憶體空間是一個常見的隱患-->
----
<!-- .slide: data-transition="convex" -->
### 建立自訂義的型別驗證
v0.0.1
```javascript=
loop {
// --snip--
let guess: i32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
if guess < 1 || guess > 100 {
println!("The secret number will be between 1 and 100.");
continue;
}
match guess.cmp(&secret_number) {
// --snip--
}
```
----
<!-- .slide: data-transition="convex" -->
不過這樣但這樣每次都要進一次判斷式,如果很多的函式都需要這樣的檢查,這樣寫就恨很冗餘(也許也會小小的引響到效能)
----
<!-- .slide: data-transition="convex" -->
```javascript=
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess {
value
}
}
pub fn value(&self) -> u32 {
self.value
}
}
```
----
<!-- .slide: data-transition="convex" -->
v0.0.2
```diff=
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
- Ok(num) => num,
+ Ok(num) => Guess::new(num).value(),
Err(_) => continue,
};
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
+ pub struct Guess {
+ value: u32,
+ }
+
+ impl Guess {
+ pub fn new(value: u32) -> Guess {
+ if value < 1 || value > 100 {
+ panic!("Guess value must be between 1 and +100, got {}.", value);
+ }
+
+ Guess {
+ value
+ }
+ }
+
+ pub fn value(&self) -> u32 {
+ self.value
+ }
+ }
```
---
<!-- .slide: data-transition="convex" -->
## Thanks for listening ~
{"metaMigratedAt":"2023-06-14T18:22:36.042Z","metaMigratedFrom":"Content","title":"<h2>ch9. Error Handling</h2>","breaks":true,"contributors":"[{\"id\":\"69ade472-3ed3-499d-8a69-767243a31621\",\"add\":26527,\"del\":7855}]"}