<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}]"}
    1286 views