一、前言
上一篇文章中,介绍了rust中强大的trait,因此本文就来使用一下这些常用的、且需要自己手动实现的trait来完成一些功能,也就是类型转换与迭代器。
首先我们从较为复杂的类型转换讲起。
rust相比于C/C++,最让人惊艳的便是它的自动类型推导,比如当你写下面这条语句时:
let a=10;
rust编译器将能够自动推导出a的类型为i32,因为字面量10的值就是i32。
当然,这个特性在C/C++中可以使用auto关键字实现,包括本文要介绍的类型转换,C/C++同样也可以实现、甚至可能更加方便(比如强制转换?)。
但rust能够通过人为指定返回值类型来推断函数返回值类型在C/C++中却是无法实现的(也就是本文要介绍的功能)。
包括rust提供了安全性保证、其类型相当直观、即使是枚举类型也能实现方法进行任意类型转换,加上其简练优雅的语法,在体验上C/C++真的很难与之相比。
二、基本理解
类型转换在我的感知中,最实用的一个功能其实是枚举类型:
enum Test {
One,
Two,
Three,
}
比如上面这个枚举类型,当我们想要将其作为字符串输出时,一般可能就得这样做:
fn main() {
let v = Test::One;
let str = match v {
Test::One => "One",
Test::Two => "Two",
Test::Three => "Three",
};
println!("{}", str);
}
这样做当然是可以的,只不过不够简练优雅。
这样的用途是很多的,比如你想要将其枚举类型值存入数据库中,你无法直接输入枚举类型,必须要先将其转化为字符串。
所以我们还可以将其封装为一个函数进行调用:
fn main() {
let v = Test::One;
let str = to_str(v);
println!("{}", str);
}
fn to_str(v: Test) -> &'static str {
match v {
Test::One => "One",
Test::Two => "Two",
Test::Three => "Three",
}
}
这样简练了不少,但仍然不够优雅,因为这个to_str
函数现在已经固定只能让Test
类型作为参数使用了,但这个函数名却是一个比较常见的名字。
如果放在外面,别的类型也想要使用这个函数名怎么办呢?就会导致重名问题。
所以还能继续改进:
impl Test {
pub fn to_str(&self) -> &'static str {
match self {
Test::One => "One",
Test::Two => "Two",
Test::Three => "Three",
}
}
}
fn main() {
let v = Test::One;
let str = v.to_str();
println!("{}", str);
}
此时就很直观了,就是调用枚举变量v上的to_str函数,将其转换为字符串。
更进一步,如果我想将其转换为数字类型,那么可能还需要写上这样一个函数:
impl Test {
pub fn to_str(&self) -> &'static str {
match self {
Test::One => "One",
Test::Two => "Two",
Test::Three => "Three",
}
}
pub fn to_num(&self) -> i32 {
match self {
Test::One => 1,
Test::Two => 2,
Test::Three => 3,
}
}
}
这种情况是很常见的,我们常常需要将一个类型转化为多种数据类型。
这样做虽然可以,但在调用的时候可能就不太优雅了: