add type conversions - From/Into
This commit is contained in:
parent
2250413225
commit
12cca75b20
|
@ -0,0 +1,139 @@
|
||||||
|
1.
|
||||||
|
```rust
|
||||||
|
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);
|
||||||
|
|
||||||
|
let i3: u32 = 'a'.into();
|
||||||
|
|
||||||
|
let s: String = 'a'.into();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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);
|
||||||
|
|
||||||
|
let i3: u32 = 'a' as u32 ;
|
||||||
|
|
||||||
|
let s: String = String::from('a');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2.
|
||||||
|
```rust
|
||||||
|
// From is now included in `std::prelude`, so there is no need to introduce it into the current scope
|
||||||
|
// use std::convert::From;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Number {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Number {
|
||||||
|
// IMPLEMENT `from` method
|
||||||
|
fn from(item: i32) -> Self {
|
||||||
|
Number { value: item }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let num = Number::from(30);
|
||||||
|
assert_eq!(num.value, 30);
|
||||||
|
|
||||||
|
let num: Number = 30.into();
|
||||||
|
assert_eq!(num.value, 30);
|
||||||
|
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3.
|
||||||
|
```rust
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
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> {
|
||||||
|
// ? automatically converts io::Error to CliError
|
||||||
|
let contents = fs::read_to_string(&file_name)?;
|
||||||
|
// num::ParseIntError -> CliError
|
||||||
|
let num: i32 = contents.trim().parse()?;
|
||||||
|
Ok(num)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4.
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let n: i16 = 256;
|
||||||
|
|
||||||
|
let n: u8 = match n.try_into() {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(e) => {
|
||||||
|
println!("there is an error when converting: {:?}, but we catch it", e.to_string());
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(n, 0);
|
||||||
|
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
5.
|
||||||
|
```rust,editable
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct EvenNum(i32);
|
||||||
|
|
||||||
|
impl TryFrom<i32> for EvenNum {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
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, Ok(EvenNum(8)));
|
||||||
|
let result: Result<EvenNum, ()> = 5i32.try_into();
|
||||||
|
assert_eq!(result, Err(()));
|
||||||
|
}
|
||||||
|
```
|
|
@ -99,5 +99,7 @@ fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
assert_eq!(std::mem::size_of_val(&*b), __)
|
assert_eq!(std::mem::size_of_val(&*b), __)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("Success!")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1 +1,171 @@
|
||||||
# From/Into
|
# From/Into
|
||||||
|
The `From` trait allows for a type to define how to create itself from another type, hence providing a very simple mechanism for converting between several types.
|
||||||
|
|
||||||
|
The `From` and `Into` traits are inherently linked, and this is actually part of its implementation. It means if we write something like this: `impl From<T> for U`, then we can use
|
||||||
|
`let u: U = U::from(T)` or `let u:U = T.into()`.
|
||||||
|
|
||||||
|
The `Into` trait is simply the reciprocal of the `From` trait. That is, if you have implemented the `From` trait for your type, then the `Into` trait will be automatically implemented for the same type.
|
||||||
|
|
||||||
|
Using the `Into` trait will typically require the type annotations as the compiler is unable to determine this most of the time.
|
||||||
|
|
||||||
|
For example we can easily convert `&str` into `String` :
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let my_str = "hello";
|
||||||
|
|
||||||
|
// three conversions below all depends on the fact: String implements From<&str>:
|
||||||
|
let string1 = String::from(my_str);
|
||||||
|
let string2 = my_str.to_string();
|
||||||
|
// explict type annotation is required here
|
||||||
|
let string3: String = my_str.into();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
because the standard library has already implemented this for us : `impl From<&'_ str> for String` .
|
||||||
|
|
||||||
|
Some implementations of `From` trait can be found [here](https://doc.rust-lang.org/stable/std/convert/trait.From.html#implementors).
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// FIX the error in two ways
|
||||||
|
// 1. impl From<char> for ? , maybe you should check the docs mentiond above to find the answer
|
||||||
|
// 2. a keyword from the last chapter
|
||||||
|
let i3: i32 = 'a'.into();
|
||||||
|
|
||||||
|
// FIX the error in two ways
|
||||||
|
let s: String = 'a' as String;
|
||||||
|
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implement `From` for custom types
|
||||||
|
2. 🌟🌟
|
||||||
|
```rust,editable
|
||||||
|
|
||||||
|
// From is now included in `std::prelude`, so there is no need to introduce it into the current scope
|
||||||
|
// use std::convert::From;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Number {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Number {
|
||||||
|
// IMPLEMENT `from` method
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILL in the blanks
|
||||||
|
fn main() {
|
||||||
|
let num = __(30);
|
||||||
|
assert_eq!(num.value, 30);
|
||||||
|
|
||||||
|
let num: Number = __;
|
||||||
|
assert_eq!(num.value, 30);
|
||||||
|
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 🌟🌟🌟 When performing error handling it is often useful to implement `From` trait for our own error type. Then we can use `?` to automatically convert the underlying error type to our own error type.
|
||||||
|
```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 {
|
||||||
|
// IMPLEMENT from method
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<num::ParseIntError> for CliError {
|
||||||
|
// IMPLEMENT from method
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
|
||||||
|
// ? automatically converts io::Error to 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
|
||||||
|
Similar to `From` and `Into`, `TryFrom` and `TryInto` are generic traits for converting between types.
|
||||||
|
|
||||||
|
Unlike `From/Into`, `TryFrom` and `TryInto` are used for fallible conversions and return a `Result` instead of a plain value.
|
||||||
|
|
||||||
|
4. 🌟🌟
|
||||||
|
```rust,editable
|
||||||
|
// TryFrom and TryInto are included in `std::prelude`, so there is no need to introduce it into the current scope
|
||||||
|
// use std::convert::TryInto;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let n: i16 = 256;
|
||||||
|
|
||||||
|
// Into trait has a method `into`,
|
||||||
|
// hence TryInto has a method ?
|
||||||
|
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 = ();
|
||||||
|
|
||||||
|
// IMPLEMENT `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(()));
|
||||||
|
|
||||||
|
// FILL in the blanks
|
||||||
|
let result: Result<EvenNum, ()> = 8i32.try_into();
|
||||||
|
assert_eq!(result, __);
|
||||||
|
let result: Result<EvenNum, ()> = 5i32.try_into();
|
||||||
|
assert_eq!(result, __);
|
||||||
|
|
||||||
|
println!("Success!")
|
||||||
|
}
|
||||||
|
```
|
Binary file not shown.
Loading…
Reference in New Issue