diff --git a/ChangeLog.md b/ChangeLog.md index 7384cf3..451239d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,6 +2,7 @@ ### 2022-3-20 +- Add [Result (zh)] - Add [Panics (Zh)] - Add [Type conversion - others.md (zh)] diff --git a/zh-CN/src/result-panic/result.md b/zh-CN/src/result-panic/result.md index 7af6baf..05d2f21 100644 --- a/zh-CN/src/result-panic/result.md +++ b/zh-CN/src/result-panic/result.md @@ -1 +1,210 @@ # result and ? +`Result` 是一个枚举类型用于描述返回的结果或错误,它包含两个成员(变体 variants) : + +- `Ok(T)`: 返回一个结果值 T +- `Err(e)`: 返回一个错误,`e` 是具体的错误值 + +简而言之,如果期待一个正确的结果,就返回 `Ok`,反之则是 `Err`。 + + +1. 🌟🌟 +```rust,editable + +// 填空并修复错误 +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!") +} +``` + +### ? +`?` 跟 `unwrap` 非常像,但是 `?` 会返回一个错误,而不是直接 panic. + +2. 🌟🌟 +```rust,editable + +use std::num::ParseIntError; + +// 使用 `?` 来实现 multiply +// 不要使用 unwrap ! +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), + } +} + +// 填空 +// 不要修改其它代码 +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) 是两个常用的组合器( combinator ),可以用于 `Result` (也可用于 `Option`). + +4. 🌟🌟 + +```rust,editable +use std::num::ParseIntError; + +// 使用两种方式填空: 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; + +// 使用 Result 重写后,我们使用模式匹配的方式来处理,而无需使用 `unwrap` +// 但是这种写法实在过于啰嗦.. +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), + } +} + +// 重写上面的 `multiply` ,让它尽量简介 +// 提示:使用 `and_then` 和 `map` +fn multiply1(n1_str: &str, n2_str: &str) -> Result { + // 实现... +} + +fn print(result: Result) { + match result { + Ok(n) => println!("n is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +fn main() { + let twenty = multiply1("10", "2"); + print(twenty); + + // 下面的调用会提供更有帮助的错误信息 + let tt = multiply("t", "2"); + print(tt); + + println!("Success!") +} +``` + +### 类型别名 +如果我们要在代码中到处使用 `std::result::Result` ,那毫无疑问,代码将变得特别冗长和啰嗦,对于这种情况,可以使用类型别名来解决。 + +例如在标准库中,就在大量使用这种方式来简化代码: [`io::Result`](https://doc.rust-lang.org/std/io/type.Result.html). + +6. 🌟 +```rust,editable +use std::num::ParseIntError; + +// 填空 +type __; + +// 使用上面的别名来引用原来的 `Result` 类型 +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) + }) +} + +// 同样, 这里也使用了类型别名来简化代码 +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!") +} +``` + +### 在 `fn main` 中使用 `Result` +一个典型的 `main` 函数长这样: +```rust +fn main() { + println!("Hello World!"); +} +``` +事实上 `main` 函数还可以返回一个 `Result` 类型:如果 `main` 函数内部发生了错误,那该错误会被返回并且打印出一条错误的 debug 信息。 + +```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