Rust 中的类型转换

时间:2019-11-07 18:43:43   收藏:0   阅读:135

1. as 运算符

as 运算符有点像 C 中的强制类型转换,区别在于,它只能用于原始类型(i32i64f32
f64u8u32char 等类型),并且它是安全的

在 Rust 中,不同的数值类型是不能进行隐式转换的,比如:

 let b: i64 = 1i32;

会出现编译错误,提示无法进行类型转换。

error[E0308]: mismatched types
 --> src\main.rs:2:18
    |
2   |     let b: i64 = 1i32;
    |                  ^^^^ expected i64, found i32
help: change the type of the numeric literal from `i32` to `i64`

这时可以使用as 进行转换。

let b: i64 = 1i32 as i64;

2. Trait From<T>Into<T>

上文说到,as 运算符之能在原始类型之间进行转换,那么对于 Struct 和 Enum 这样的类型该如何进行转换呢? 这就是我们这节的内容 From<T>Into<T>

先来看一看这两个 Trait 的结构。

pub trait From<T> {
    fn from(T) -> Self;
}
pub trait Into<T> {
    fn into(self) -> T;
}

很简单,From<T> 有一个 from 方法,Into<T> 有一个 into 方法。

一般来说,我们应该尽量优先选择实现 From<T> 而不是 Into<T> ,因为当你为 U 实现 From<T> ,这意味着你同时也为 T 隐式实现了 Into<U>

来看个例子

fn main() {
    println!("Hello, world!");
    let b: Complex = 1.into();
    println!("{:?}", b);
}
#[derive(Debug)]
struct Complex {
    re: i32,
    im: i32
}

impl From<i32> for Complex{
    fn from(re: i32) -> Self {
        Complex{
            re,
            im:0
        }
    }
}

当我为 Complex 实现 From<i32> 后,我也可以在 i32 上使用 into 方法,转换到 Complex

原始类型实现了与 as 转换相对应的 From<T>Into<T>

当你为 U 实现 From<T> 之后,你要确保这个转换一定能成功,如若有失败的可能,你应该选择为 U 实现 TryFrom<T>

3. 解引用强制多态

这次先看一个例子:

fn print(message: &str) {
    println!("{}",message);
}
fn main() {
    let message: String = "message".to_string();
    print(&message);
}

print 的形参是 &str 类型,然而在 main 中,我传递却是一个 &String 类型的实参。明显,这两个类型不相同!!Rust 为什么会通过这样的代码呢?

没错,这就是 Rust 的 解引用强制多态。

首先,需要了解一个 Deref Trait 。

#[lang = "deref"]
pub trait Deref {

    type Target: ?Sized;

    #[must_use]
    fn deref(&self) -> &Self::Target;
}

deref 方法返回一个 &Target 类型的引用。

回忆一下 Rust 中的解引用语法,当 ref 是一个引用或智能指针时,我们可以使用 *ref 的方式解引用。这是类似一个语法糖,对于 *ref 这种写法,写全应该时 *(ref.deref())

回想 Box<T> 的使用,Box<T> 实现了 Deref ,它的 deref 方法返回 &T 的引用,然后使用解引用运算符 * ,我们顺利拿到一个 T 类型的数据。也就是,你可以通过实现 Deref 以重载解引用运算符。

Deref 和这节的内容有什么关系呢?

T 实现了 Deref<Target=U> 时,对于需要 &U 的地方,你可以提供一个 &T 类型的数据,Rust会为你自动调用 deref 方法,而这个过程可以重复多次。

比如,我自定义类型 P 实现了 Deref<Target=String> ,那么可以把 &P 类型变量传递给一个 &str 类型变量。&P -> &String -> &str ,伪代码: &P.deref().deref()

回到这节开头的例子,print(&message) 相当于 print((&message).deref()) ,正好是一个 &str 类型。

原文:https://www.cnblogs.com/ywxt/p/11801778.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!