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;
  • 为什么它是安全的?

    尝试以下代码:

    let b = 1i32 as char;

    编译器错误:

    error[E0604]: only `u8` can be cast as `char`, not `i32`
    --> src\main.rs:2:13
    |
    2 | let b = 1i32 as char;
    | ^^^^^^^^^^^^

    可见在不相关的类型之间,Rust 会拒绝转换,这也避免了运行时错误。

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>

  • 什么时候该使用 Into<T>

    Into<T> 被设计出来,总有该用到的地方。那什么时候该使用呢?

    先复习一下 Rust 中的 孤儿原则

    在声明trait和impl trait的时候,Rust规定了一个Orphan Rule(孤儿规则):impl块要么与trait的声明在同一个的crate中,要么与类型的声明在同一个crate中。

    也就是说,不能在一个crate中,针对一个外部的类型,实现一个外部的trait。

    因为在其它的crate中,一个类型没有实现一个trait,很可能是有意的设计。

    如果我们在使用其它的crate的时候,强行把它们“拉郎配”,是会制造出bug的。

    比如说,我们写了一个程序,引用了外部库lib1和lib2,lib1中声明了一个trait T,lib2中声明了一个struct S ,我们不能在自己的程序中针对S实现T。

    这也意味着,上游开发者在给别人写库的时候,尤其要注意。

    一些比较常见的标准库中的 trait,比如 Display Debug ToString Default 等,应该尽可能地提供好。

    否则,使用这个库的下游开发者,是没办法帮我们把这些 trait 实现的。

    同理,如果是匿名impl,那么这个impl块必须与类型本身存在于同一个模块中。

    来自 F001 https://zhuanlan.zhihu.com/p/21568827

    显然, From<T> 不属于当前 crate ,当你要实现当前 crate 中的类型 T 转换到其他 crate 中的类型 U 时,如果选择为 U 实现 From<T> ,由于孤儿原则,编译器会阻止你这么做。这时我们就可以选择为 T 实现 Into<U>

    注意,和 From<T> 不同,实现 Into<U> 之后并不会隐式实现 From<T> ,这点需特别注意。

  • From<T> 的妙用

    回忆一下 Rust 的 ? 操作符,它被用于 返回值为 Result<T,E> 或者 Option<T> 的函数。回想一下,它是如何处理 Err(E) 的。

    fn apply() -> Result<i32,i32> {
    Err(1)
    }
    fn main() -> Result<(),i64> {
    let a = apply()?;
    Ok(())
    }

    上面的例子是可以通过编译的,既然 Rust 中的数值类型是不能隐式转换的,那么,当返回 Err(i32) 时是如何转换到 Err(i64) 的呢?这其实是一个 Rust 的语法糖。展开后的代码类似于下面:

    fn apply() -> Result<i32,i32> {
    Err(1)
    }
    fn main() -> Result<(),i64> {
    let a = match apply() {
    Ok(v) => v,
    Err(e) => return Err(i64::from(e)),
    };
    Ok(())
    }

    也就是说,Rust 会自动调用目标类 from 方法进行转换。

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 类型。

Rust 中的类型转换的更多相关文章

  1. JavaScript中数据类型转换总结

    JavaScript中数据类型转换总结 在js中,数据类型转换分为显式数据类型转换和隐式数据类型转换. 1, 显式数据类型转换 a:转数字: 1)Number转换: 代码: var a = " ...

  2. java中强制类型转换

    在Java中强制类型转换分为基本数据类型和引用数据类型两种,这里我们讨论的后者,也就是引用数据类型的强制类型转换. 在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需 ...

  3. JS中String类型转换Date类型 并 计算时间差

    JS中String类型转换Date类型 1.比较常用的方法,但繁琐,参考如下:主要使用Date的构造方法:Date(int year , int month , int day)<script& ...

  4. SQL中的类型转换

    SQL中的类型转换一直是以块心病,因为用得比较少,所以每次想用的时候都要想半天,恰好这段时间比较空,整理整理.今天写个标题先.

  5. Rust 中的继承与代码复用

    在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...

  6. Struts2中的类型转换

    1.     Struts2中的类型转换 我们知道通过HTTP提交到后台的数据,都是字符串的形式,而我们需要的数据类型当然不只字符串类型一种.所以,我们需要类型转换! 在Struts2中,类型转换的概 ...

  7. java中的类型转换

    java中的类型转换分为两种 自动类型转换 要实现数据的自动类型转换必须同时满足下面两个条件 两种数据类型彼此兼容 目标类型的取值范围大于原类型范围 强制类型转换 当两种数据类型彼此不兼容,或者说目标 ...

  8. HQL语句中数据类型转换,及hibernate中createQuery执行hql报错

    一.HQL语句中数据类型转换: 我们需要从数据库中取出序号最大的记录,想到的方法就是使用order by子句进行排序(desc倒序),然后取出第一个对象,可是当初设计数据库时(我们是在原来的数据库的基 ...

  9. Java中数据类型转换&基本类型变量和对象型变量

    1.Java的数据类型分为三大类 布尔型,字符型和数值型 其中数值型又分为整型和浮点型 2.Java的变量类型 布尔型 boolean 字符型 char 整型    byte,short,int,lo ...

随机推荐

  1. C# HttpWebRequest 后台调用接口上传大文件以及其他参数

    直接上代码,包各位看客能用!!! 1.首先请求参数的封装 /// <summary> /// 上传文件 - 请求参数类 /// </summary> public class ...

  2. python——成语接龙小游戏

    小试牛刀的简易成语接龙. 思路—— 1.网上下载成语字典的txt版本 2.通过python进行处理得到格式化的成语,并整理成字典(python字典查找速度快) 3.python程序,查找 用户输入的最 ...

  3. redis查找大key

    redis中查找出比较大的key 下面直接上代码 (请在测试机上测试) #!/usr/bin/env python import sys import redis def check_big_key( ...

  4. springmvc中重定向该如何处理?

    如果登录成功,会重定向到系统首页 response.sendRedirect("jsp/frame.jsp"); 在springmvc中,应该如何处理?是否可以直接使用 retur ...

  5. SpringBoot第二十五篇:SpringBoot与AOP

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11457867.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言   作者在实际 ...

  6. css父元素透明度(opacity)对子元素的影响

    首先子元素会继承父元素的透明度: 设置父元素opacity:0.5,子元素不设置opacity,子元素会受到父元素opacity的影响,也会有0.5的透明度. 其次子元素的透明度是基于父元素的透明度计 ...

  7. 学以致用,通过字节码理解:Java的内部类与外部类之私有域访问

    目录: 内部类的定义及用处 打开字节码理解内部类 一.内部类的定义及用处 内部类(inner class)是定义在另一个类中的类.使用内部类,我们可以: 访问该类定义所在的作用域中的数据,包括私有的数 ...

  8. linux系统定时发送邮件

    Linux Centos7系统下利用自带的mail发送邮件服务 简介 本章分为五部分. 第一部分是基于虚拟机下的CentOS 7环境定时发送邮件: 第二部分是基于在阿里云购买的CentOS 7服务器环 ...

  9. Jsoup-解析HTML工具(简单爬虫工具)

    Jsoup-解析HTML工具(简单爬虫工具) 一.简介 ​ jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS ...

  10. Web前端安全之iframe

    防嵌套网页 比如,最出名的clickhacking就是使用iframe来 拦截click事件.因为iframe享有着click的最优先权,当有人在伪造的主页中进行点击的话,如果点在iframe上,则会 ...