add zh/from-into.md
This commit is contained in:
parent
e0165ed074
commit
6babd59cc5
|
@ -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"
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ fn main() {
|
|||
```
|
||||
|
||||
|
||||
1. 🌟🌟🌟
|
||||
5. 🌟🌟🌟
|
||||
```rust,editable
|
||||
fn main() {
|
||||
let arr :[u64; 13] = [0; 13];
|
||||
|
|
|
@ -1 +1,168 @@
|
|||
# From/Into
|
||||
`From` 特征允许让一个类型定义如何基于另一个类型来创建自己,因此它提供了一个很方便的类型转换的方式。
|
||||
|
||||
`From` 和 `Into` 是配对的,我们只要实现了前者,那后者就会自动被实现:只要实现了 `impl From<T> 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<bool> 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<char> 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<i32> 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<io::Error> for CliError {
|
||||
// 实现 from 方法
|
||||
}
|
||||
|
||||
impl From<num::ParseIntError> for CliError {
|
||||
// 实现 from 方法
|
||||
}
|
||||
|
||||
fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
|
||||
// ? 自动将 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<i32> for EvenNum {
|
||||
type Error = ();
|
||||
|
||||
// 实现 `try_from`
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
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<EvenNum, ()> = 8i32.try_into();
|
||||
assert_eq!(result, __);
|
||||
let result: Result<EvenNum, ()> = 5i32.try_into();
|
||||
assert_eq!(result, __);
|
||||
|
||||
println!("Success!")
|
||||
}
|
||||
```
|
Loading…
Reference in New Issue