From 553f7b1648db1e4399dcd4356ec4a7b41edd7628 Mon Sep 17 00:00:00 2001 From: sunface Date: Fri, 11 Mar 2022 15:45:03 +0800 Subject: [PATCH 1/5] add one exercise in patterns.md --- solutions/pattern-match/patterns.md | 13 +++++++++++++ src/pattern-match/patterns.md | 15 +++++++++++++++ zh-CN/src/pattern-match/patterns.md | 15 +++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/solutions/pattern-match/patterns.md b/solutions/pattern-match/patterns.md index 17149b8..18b9ee3 100644 --- a/solutions/pattern-match/patterns.md +++ b/solutions/pattern-match/patterns.md @@ -85,4 +85,17 @@ fn main() { } } } +``` + +6. +```rust +fn main() { + let mut v = String::from("hello,"); + let r = &mut v; + + match r { + // The type of value is &mut String + value => value.push_str(" world!") + } +} ``` \ No newline at end of file diff --git a/src/pattern-match/patterns.md b/src/pattern-match/patterns.md index d438705..cddc1e2 100644 --- a/src/pattern-match/patterns.md +++ b/src/pattern-match/patterns.md @@ -101,4 +101,19 @@ fn main() { } ``` +6. 🌟🌟 Using pattern `&mut V` to match a mutable reference needs you to be very careful due to `V` being a value after matching +```rust,editable + +// FIX the error with least changing +// DON'T remove any code line +fn main() { + let mut v = String::from("hello,"); + let r = &mut v; + + match r { + &mut value => value.push_str(" world!") + } +} +```` + > You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it \ No newline at end of file diff --git a/zh-CN/src/pattern-match/patterns.md b/zh-CN/src/pattern-match/patterns.md index d45c688..e9ef131 100644 --- a/zh-CN/src/pattern-match/patterns.md +++ b/zh-CN/src/pattern-match/patterns.md @@ -97,4 +97,19 @@ fn main() { } ``` +6. 🌟🌟 使用模式 `&mut V` 去匹配一个可变引用时,你需要格外小心,因为匹配出来的 `V` 是一个值,而不是可变引用 +```rust,editable + +// 修复错误,尽量少地修改代码 +// 不要移除任何代码行 +fn main() { + let mut v = String::from("hello,"); + let r = &mut v; + + match r { + &mut value => value.push_str(" world!") + } +} +```` + > 你可以在[这里](https://github.com/sunface/rust-by-practice)找到答案(在 solutions 路径下) \ No newline at end of file From 76b987152c5181779f218f64ed092ee081222913 Mon Sep 17 00:00:00 2001 From: sunface Date: Fri, 11 Mar 2022 15:46:02 +0800 Subject: [PATCH 2/5] add one exercise in patterns.md --- ChangeLog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 56e1695..834834d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,10 @@ # ChangeLog +### 2022-03-11 + +- Add one exercise in [Patterns](https://practice.rs/pattern-match/patterns.html) + + ### 2022-03-10 - Add [Type conversions - From/Into](https://practice.rs/type-conversions/from-into.html) From 3911486d5aa070858f8984df8a31ee3692958c6f Mon Sep 17 00:00:00 2001 From: sunface Date: Fri, 11 Mar 2022 17:06:25 +0800 Subject: [PATCH 3/5] add chapter: Result and ? --- solutions/result-panic/result.md | 177 ++++++++++++++++++++++++++ src/result-panic/result.md | 211 +++++++++++++++++++++++++++++++ 2 files changed, 388 insertions(+) create mode 100644 solutions/result-panic/result.md diff --git a/solutions/result-panic/result.md b/solutions/result-panic/result.md new file mode 100644 index 0000000..0babab9 --- /dev/null +++ b/solutions/result-panic/result.md @@ -0,0 +1,177 @@ +1. +```rust +use std::num::ParseIntError; + +fn multiply(n1_str: &str, n2_str: &str) -> Result { + let n1 = n1_str.parse::(); + let n2 = n2_str.parse::(); + Ok(n1.unwrap() * n2.unwrap()) +} + +fn main() { + let result = multiply("10", "2"); + assert_eq!(result, Ok(20)); + + let result = multiply("4", "2"); + assert_eq!(result.unwrap(), 8); + + println!("Success!") +} +``` + +2. +```rust +use std::num::ParseIntError; + +// IMPLEMENT multiply with ? +// DON'T use unwrap here +fn multiply(n1_str: &str, n2_str: &str) -> Result { + let n1 = n1_str.parse::()?; + let n2 = n2_str.parse::()?; + Ok(n1 * n2) +} + +fn main() { + assert_eq!(multiply("3", "4").unwrap(), 12); + println!("Success!") +} +``` + +3. +```rust +use std::fs::File; +use std::io::{self, Read}; + +fn read_file1() -> Result { + 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), + } +} + +fn read_file2() -> Result { + let mut s = String::new(); + + File::open("hello.txt")?.read_to_string(&mut s)?; + + Ok(s) +} + +fn main() { + assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string()); + println!("Success!") +} +``` + +4. +```rust +use std::num::ParseIntError; + +fn add_two(n_str: &str) -> Result { + n_str.parse::().map(|num| num +2) +} + +fn main() { + assert_eq!(add_two("4").unwrap(), 6); + + println!("Success!") +} +``` + +```rust +use std::num::ParseIntError; + +fn add_two(n_str: &str) -> Result { + n_str.parse::().and_then(|num| Ok(num +2)) +} + +fn main() { + assert_eq!(add_two("4").unwrap(), 6); + + println!("Success!") +} +``` + +5. +```rust +use std::num::ParseIntError; + +// With the return type rewritten, we use pattern matching without `unwrap()`. +// But it's so Verbose.. +fn multiply(n1_str: &str, n2_str: &str) -> Result { + match n1_str.parse::() { + Ok(n1) => { + match n2_str.parse::() { + Ok(n2) => { + Ok(n1 * n2) + }, + Err(e) => Err(e), + } + }, + Err(e) => Err(e), + } +} + +// Rewriting `multiply` to make it succinct +// You MUST USING `and_then` and `map` here +fn multiply1(n1_str: &str, n2_str: &str) -> Result { + // IMPLEMENT... + n1_str.parse::().and_then(|n1| { + n2_str.parse::().map(|n2| n1 * n2) + }) +} + +fn print(result: Result) { + match result { + Ok(n) => println!("n is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +fn main() { + // This still presents a reasonable answer. + let twenty = multiply1("10", "2"); + print(twenty); + + // The following now provides a much more helpful error message. + let tt = multiply("t", "2"); + print(tt); + + println!("Success!") +} +``` + +6. +```rust +use std::num::ParseIntError; + +// Define a generic alias for a `Result` with the error type `ParseIntError`. +type Res = Result; + +// Use the above alias to refer to our specific `Result` type. +fn multiply(first_number_str: &str, second_number_str: &str) -> Res { + first_number_str.parse::().and_then(|first_number| { + second_number_str.parse::().map(|second_number| first_number * second_number) + }) +} + +// Here, the alias again allows us to save some space. +fn print(result: Res) { + match result { + Ok(n) => println!("n is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +fn main() { + print(multiply("10", "2")); + print(multiply("t", "2")); +} +``` \ No newline at end of file diff --git a/src/result-panic/result.md b/src/result-panic/result.md index 7af6baf..064277b 100644 --- a/src/result-panic/result.md +++ b/src/result-panic/result.md @@ -1 +1,212 @@ # result and ? +`Result` is an enum to describe possible errors. It has two variants: + +- `Ok(T)`: a value T was found +- `Err(e)`: An error was found with a value `e` + +In short words, the expected outcome is `Ok`, while the unexpected outcome is `Err`. + +1. 🌟🌟 +```rust,editable + +// FILL in the blanks and FIX the errors +use std::num::ParseIntError; + +fn multiply(n1_str: &str, n2_str: &str) -> __ { + let n1 = n1_str.parse::(); + let n2 = n2_str.parse::(); + Ok(n1.unwrap() * n2.unwrap()) +} + +fn main() { + let result = multiply("10", "2"); + assert_eq!(result, __); + + let result = multiply("t", "2"); + assert_eq!(result.__, 8); + + println!("Success!") +} +``` + +### ? +`?` is almost exactly equivalent to `unwrap`, but `?` returns instead of panic on `Err`. + +2. 🌟🌟 +```rust,editable + +use std::num::ParseIntError; + +// IMPLEMENT multiply with ? +// DON'T use unwrap here +fn multiply(n1_str: &str, n2_str: &str) -> __ { +} + +fn main() { + assert_eq!(multiply("3", "4").unwrap(), 12); + println!("Success!") +} +``` + +3. 🌟🌟 +```rust,editable + +use std::fs::File; +use std::io::{self, Read}; + +fn read_file1() -> Result { + 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), + } +} + +// FILL in the blanks with one code line +// DON'T change any code else +fn read_file2() -> Result { + let mut s = String::new(); + + __; + + Ok(s) +} + +fn main() { + assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string()); + println!("Success!") +} +``` + +### map & and_then +[map](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.map) and [and_then](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.and_then) are two common combinators for `Result` (also for `Option`). + +4. 🌟🌟 + +```rust,editable +use std::num::ParseIntError; + +// FILL in the blank in two ways: map, and then +fn add_two(n_str: &str) -> Result { + n_str.parse::().__ +} + +fn main() { + assert_eq!(add_two("4").unwrap(), 6); + + println!("Success!") +} +``` + +5. 🌟🌟🌟 +```rust,editable +use std::num::ParseIntError; + +// With the return type rewritten, we use pattern matching without `unwrap()`. +// But it's so Verbose.. +fn multiply(n1_str: &str, n2_str: &str) -> Result { + match n1_str.parse::() { + Ok(n1) => { + match n2_str.parse::() { + Ok(n2) => { + Ok(n1 * n2) + }, + Err(e) => Err(e), + } + }, + Err(e) => Err(e), + } +} + +// Rewriting `multiply` to make it succinct +// You should use BOTH of `and_then` and `map` here. +fn multiply1(n1_str: &str, n2_str: &str) -> Result { + // IMPLEMENT... +} + +fn print(result: Result) { + match result { + Ok(n) => println!("n is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +fn main() { + // This still presents a reasonable answer. + let twenty = multiply1("10", "2"); + print(twenty); + + // The following now provides a much more helpful error message. + let tt = multiply("t", "2"); + print(tt); + + println!("Success!") +} +``` + +### Type alias +Using `std::result::Result` everywhere is verbose and tedious, we can use alias for this purpose. + +At a module level, creating aliases can be particularly helpful. Errors found in the a specific module often has the same `Err` type, so a single alias can succinctly defined all associated `Results`. This is so useful even the `std` library even supplies one: [`io::Result`](https://doc.rust-lang.org/std/io/type.Result.html). + +6. 🌟 +```rust,editable +use std::num::ParseIntError; + +// FILL in the blank +type __; + +// Use the above alias to refer to our specific `Result` type. +fn multiply(first_number_str: &str, second_number_str: &str) -> Res { + first_number_str.parse::().and_then(|first_number| { + second_number_str.parse::().map(|second_number| first_number * second_number) + }) +} + +// Here, the alias again allows us to save some space. +fn print(result: Res) { + match result { + Ok(n) => println!("n is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +fn main() { + print(multiply("10", "2")); + print(multiply("t", "2")); + + println!("Success!") +} +``` + +### Using Result in `fn main` +Typically `the` main function will look like this: +```rust +fn main() { + println!("Hello World!"); +} +``` + +However `main` is also able to have a return type of `Result`. If an error occurs within the `main` function it will return an error code and print a debug representation of the error( Debug trait ). + +The following example shows such a scenario: +```rust,editable + +use std::num::ParseIntError; + +fn main() -> Result<(), ParseIntError> { + let number_str = "10"; + let number = match number_str.parse::() { + Ok(number) => number, + Err(e) => return Err(e), + }; + println!("{}", number); + Ok(()) +} +``` \ No newline at end of file From f3fe9c866303dbd86c51d8213583f75b692e461a Mon Sep 17 00:00:00 2001 From: sunface Date: Fri, 11 Mar 2022 17:07:37 +0800 Subject: [PATCH 4/5] add chapter: Result and ? --- ChangeLog.md | 2 +- Readme.md | 2 +- src/SUMMARY.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 834834d..3482e37 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -3,7 +3,7 @@ ### 2022-03-11 - Add one exercise in [Patterns](https://practice.rs/pattern-match/patterns.html) - +- Add [Result and ?](https://practice.rs/result-panic/result.html) ### 2022-03-10 diff --git a/Readme.md b/Readme.md index 1ac6268..1b2a612 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,7 @@ This book was designed for easily diving into and get skilled with Rust, and it's very easy to use: All you need to do is to make each exercise compile without ERRORS and Panics ! -> 🎊 Updated on 2022-03-10: Add [Panics](https://practice.rs/result-panic/panic.html) +> 🎊 Updated on 2022-03-11: Add [Result and ?](https://practice.rs/result-panic/result.html) ## Reading online diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 919011e..62baa6d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -38,7 +38,7 @@ - [Others](type-conversions/others.md) - [Result and panic](result-panic/intro.md) - [panic!](result-panic/panic.md) - - [result and ?](result-panic/result.md) + - [Result and ?](result-panic/result.md) - [Crate and module TODO](crate-module/intro.md) - [Crate](crate-module/crate.md) - [Module](crate-module/module.md) From 185068e4cfa04a54902dd4d6fd7d146c41a3c5b8 Mon Sep 17 00:00:00 2001 From: sunface Date: Fri, 11 Mar 2022 17:16:51 +0800 Subject: [PATCH 5/5] remove .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index e4b8f743cec88e0186a653e541daecb06c5fc116..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z<-brW7Fug&r5Y7ED_$h?h|73mDOZN=;1BV9b^zHHT8jSzpK}@p+ut z-GIfMMeGdhe)GGV{UH0p7~|tb*k{aUj9JhSIVv@R?%L3nNk-&2Mm7&(8G!W>%uVdC z1AcphWh`Y6LGk_j<0#7==aX+Wn%g@qt7UbpJMT#rUhe0MZ0x5uXkAJf2bJyzSJAAP z+Iwd*$^9sqrK%tbXOMDx9VMYG#&VH_nX2`4z-n9Vsoh;J2mMh`44vauPb^OcPEQ;S zN2^ua+CMlvy_i17FNu89baG%@$*#c)-a#>|dG*pHmdPV{s_ZI@kQg8ahyh|?vl%ew zg4Nk<8ff*z05MR*0PYV08lr2k)Tp)&=7p`UpzfkFnyBet{28e-m1{&J5@%%rBU#9kvzg|KX zF+dFbGX{8b;!Vb|D08;{SRS6W0@^(^6wE780ResO5&#D7BV85Lae+GIxduy(I12hz QIUrpG6d}|R1HZt)7m%b$egFUf diff --git a/.gitignore b/.gitignore index e9c0728..bd3a7c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -book \ No newline at end of file +book +.DS_Store