From 6babd59cc53bcd2ce1c97da56a86fdaaa4fc79fb Mon Sep 17 00:00:00 2001 From: sunface Date: Fri, 18 Mar 2022 17:34:01 +0800 Subject: [PATCH] add zh/from-into.md --- zh-CN/book.toml | 2 +- zh-CN/src/type-conversions/as.md | 2 +- zh-CN/src/type-conversions/from-into.md | 167 ++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) diff --git a/zh-CN/book.toml b/zh-CN/book.toml index 591d652..f6c4e69 100644 --- a/zh-CN/book.toml +++ b/zh-CN/book.toml @@ -1,6 +1,6 @@ [book] title = "Rust By Practice( Rust 练习实践 )" -description = "Practice Rust with example, exercise and hand-to-hand projects. Written with ❤️ by https://course.rs team" +description = "Practice Rust by example, exercise and hand-to-hand projects. Written with ❤️ by https://course.rs team" authors = ["sunface, https://im.dev"] language = "en" diff --git a/zh-CN/src/type-conversions/as.md b/zh-CN/src/type-conversions/as.md index 30874b2..c7da3b0 100644 --- a/zh-CN/src/type-conversions/as.md +++ b/zh-CN/src/type-conversions/as.md @@ -88,7 +88,7 @@ fn main() { ``` -1. 🌟🌟🌟 +5. 🌟🌟🌟 ```rust,editable fn main() { let arr :[u64; 13] = [0; 13]; diff --git a/zh-CN/src/type-conversions/from-into.md b/zh-CN/src/type-conversions/from-into.md index fef65e6..83a568e 100644 --- a/zh-CN/src/type-conversions/from-into.md +++ b/zh-CN/src/type-conversions/from-into.md @@ -1 +1,168 @@ # From/Into +`From` 特征允许让一个类型定义如何基于另一个类型来创建自己,因此它提供了一个很方便的类型转换的方式。 + +`From` 和 `Into` 是配对的,我们只要实现了前者,那后者就会自动被实现:只要实现了 `impl From for U`, 就可以使用以下两个方法: `let u: U = U::from(T)` 和 `let u:U = T.into()`,前者由 `From` 特征提供,而后者由自动实现的 `Into` 特征提供。 + +需要注意的是,当使用 `into` 方法时,你需要进行显式地类型标注,因为编译器很可能无法帮我们推导出所需的类型。 + + +来看一个例子,我们可以简单的将 `&str` 转换成 `String`。` +```rust +fn main() { + let my_str = "hello"; + + // 以下三个转换都依赖于一个事实:String 实现了 From<&str> 特征 + let string1 = String::from(my_str); + let string2 = my_str.to_string(); + // 这里需要显式地类型标注 + let string3: String = my_str.into(); +} +``` + +这种转换可以发生是因为标准库已经帮我们实现了 `From` 特征: `impl From<&'_ str> for String`。你还可以在[这里](https://doc.rust-lang.org/stable/std/convert/trait.From.html#implementors))找到其它实现 `From` 特征的常用类型。 + + +1. 🌟🌟🌟 +```rust,editable + +fn main() { + // impl From for i32 + let i1:i32 = false.into(); + let i2:i32 = i32::from(false); + assert_eq!(i1, i2); + assert_eq!(i1, 0); + + // 使用两种方式修复错误 + // 1. 哪个类型实现 From 特征 : impl From for ? , 你可以查看一下之前提到的文档,来找到合适的类型 + // 2. 上一章节中介绍过的某个关键字 + let i3: i32 = 'a'.into(); + + // 使用两种方法来解决错误 + let s: String = 'a' as String; + + println!("Success!") +} +``` + +### 为自定义类型实现 `From` 特征 +2. 🌟🌟 +```rust,editable + +// From 被包含在 `std::prelude` 中,因此我们没必要手动将其引入到当前作用域来 +// use std::convert::From; + +#[derive(Debug)] +struct Number { + value: i32, +} + +impl From for Number { + // 实现 `from` 方法 +} + +// 填空 +fn main() { + let num = __(30); + assert_eq!(num.value, 30); + + let num: Number = __; + assert_eq!(num.value, 30); + + println!("Success!") +} +``` + +3. 🌟🌟🌟 当执行错误处理时,为我们自定义的错误类型实现 `From` 特征是非常有用。这样就可以通过 `?` 自动将某个错误类型转换成我们自定义的错误类型 +```rust,editable + +use std::fs; +use std::io; +use std::num; + +enum CliError { + IoError(io::Error), + ParseError(num::ParseIntError), +} + +impl From for CliError { + // 实现 from 方法 +} + +impl From for CliError { + // 实现 from 方法 +} + +fn open_and_parse_file(file_name: &str) -> Result { + // ? 自动将 io::Error 转换成 CliError + let contents = fs::read_to_string(&file_name)?; + // num::ParseIntError -> CliError + let num: i32 = contents.trim().parse()?; + Ok(num) +} + +fn main() { + println!("Success!") +} +``` + + +### TryFrom/TryInto +类似于 `From` 和 `Into`, `TryFrom` 和 `TryInto` 也是用于类型转换的泛型特。 + +但是又与 `From/Into` 不同, `TryFrom` 和 `TryInto` 可以对转换后的失败进行处理,然后返回一个 `Result`。 + +4. 🌟🌟 +```rust,editable +// TryFrom 和 TryInto 也被包含在 `std::prelude` 中, 因此以下引入是没必要的 +// use std::convert::TryInto; + +fn main() { + let n: i16 = 256; + + // Into 特征拥有一个方法`into`, + // 因此 TryInto 有一个方法是 ? + let n: u8 = match n.__() { + Ok(n) => n, + Err(e) => { + println!("there is an error when converting: {:?}, but we catch it", e.to_string()); + 0 + } + }; + + assert_eq!(n, __); + + println!("Success!") +} +``` + +5. 🌟🌟🌟 +```rust,editable +#[derive(Debug, PartialEq)] +struct EvenNum(i32); + +impl TryFrom for EvenNum { + type Error = (); + + // 实现 `try_from` + fn try_from(value: i32) -> Result { + if value % 2 == 0 { + Ok(EvenNum(value)) + } else { + Err(()) + } + } +} + +fn main() { + assert_eq!(EvenNum::try_from(8), Ok(EvenNum(8))); + assert_eq!(EvenNum::try_from(5), Err(())); + + // 填空 + let result: Result = 8i32.try_into(); + assert_eq!(result, __); + let result: Result = 5i32.try_into(); + assert_eq!(result, __); + + println!("Success!") +} +``` \ No newline at end of file