类型转换(Rust入门)

本文章参考自官方学习文档及社区学习文档以下是参考链接:

官方:

社区:

直接上手学习推荐:

概述点

  • FromInto
  • TryFromTryInto
  • ToStringFromStr

Rust 使用 trait 解决类型之间的转换问题。最一般的转换会用到 Frominto 两个 trait。不过,即便常见的情况也可能会用到特别的 trait,尤其是从 String 转换到别的类型,以及把别的类型转换到 String 时。

From和Into

FromInto两个trait是内在联系的,事实上这是他们实现的重要部分:如果能把类型 A 转换成类型 B,那么很容易相信我们也能把类型 B 转换成类型 A

From

From trait 允许一种类型定义 “怎么根据另一种类型生成自己”,因此它提供了一种类型转换的简单机制。在标准库中有无数 From 的实现,规定了原生类型及其他常见类型的转换功能。

比如,可以很容易把str转换成String:

1
2
let my_str = "hello";
let my_string = String::from(my_str);

也可以自定义类型转换机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use std::convert::From;

#[derive(Debug)]
struct Number {
value: i32,
}

impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}

fn main() {
let num = Number::from(30);
println!("My number is {:?}", num);
}

Into

Into trait就是把Fromtrait倒过来而已。也就是说,如果你为你的类型实现了From,那么同时你也就显式实现了Into

使用Intotrait通常要求指明要转化到的类型,因为编译器大多数时候不能推断它。不过考虑到我们显式实现了 Into,这点代价不值一提。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use std::convert::From;

#[derive(Debug)]
struct Number {
value: i32,
}

impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}

fn main() {
let int = 5;
// 试试删除类型说明
let num: Number = int.into();
println!("My number is {:?}", num);
}

TryFrom and TryInto

类似于 FromIntoTryFromTryInto 是类型转换的通用 trait。不同于 From/Into 的是,TryFromTryInto trait 用于易出错的转换,也正因如此,其返回值是 Result 型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
use std::convert::TryFrom;
use std::convert::TryInto;

#[derive(Debug, PartialEq)]
struct EvenNumber(i32);

impl TryFrom<i32> for EvenNumber {
type Error = ();

fn try_from(value: i32) -> Result<Self, Self::Error> {
if value % 2 == 0 {
Ok(EvenNumber(value))
} else {
Err(())
}
}
}

fn main() {
// TryFrom

assert_eq!(EvenNumber::try_from(8), Ok(EvenNumber(8)));
assert_eq!(EvenNumber::try_from(5), Err(()));

// TryInto

let result: Result<EvenNumber, ()> = 8i32.try_into();
assert_eq!(result, Ok(EvenNumber(8)));
let result: Result<EvenNumber, ()> = 5i32.try_into();
assert_eq!(result, Err(()));
}

assert_eq断言

参考链接Rust语言圣经(Rust Course)

在编写测试函数时,断言决定了我们的测试是通过还是失败,它为结果代言

断言列表
  • assert!, assert_eq!, assert_ne!, 它们会在所有模式下运行
  • debug_assert!, debug_assert_eq!, debug_assert_ne!, 它们只会在 Debug 模式下运行

ToString 和 FromStr

要把任何类型转换成 String,只需要实现那个类型的 ToString trait。然而不要直接这么做,您应该实现 fmt::Display trait,它会自动提供 ToString,并且还可以用来打印类型,就像 print! 那样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use std::string::ToString;

struct Circle {
radius: i32
}

impl ToString for Circle {
fn to_string(&self) -> String {
format!("Circle of radius {:?}", self.radius)
}
}

fn main() {
let circle = Circle { radius: 6 };
println!("{}", circle.to_string());
}

解析字符串

我们经常需要把字符串转成数字。完成这项工作的标准手段是用 parse 函数。我们得提供要转换到的类型,这可以通过不使用类型推断,或者用「涡轮鱼」语法(turbo fish,<>)实现。

只要对目标类型实现了 FromStr trait,就可以用 parse 把字符串转换成目标类型。 标准库中已经给无数种类型实现了 FromStr。如果要转换到用户定义类型,只要手动实现 FromStr 就行。

1
2
3
4
5
6
7
fn main() {
let parsed: i32 = "5".parse().unwrap();
let turbo_parsed = "10".parse::<i32>().unwrap();

let sum = parsed + turbo_parsed;
println!{"Sum: {:?}", sum};
}