# 类型转换
> [casting-between-types.md](https://github.com/rust-lang/rust/blob/master/src/doc/book/casting-between-types.md)
commit 6ba952020fbc91bad64be1ea0650bfba52e6aab4
Rust,和它对安全的关注,提供了两种不同的在不同类型间转换的方式。第一个,`as`,用于安全转换。相反,`transmute`允许任意的转换,而这是 Rust 中最危险的功能之一!
### 强制转换(Coercion)
类型间的强制转换是隐式的并没有自己的语法,不过可以写作[`as`](#)。
强转出现在`let`,`const`和`static`语句;函数调用参数;结构体初始化的字符值;和函数返回值中。
最常用的强转的例子是从引用中去掉可变性:
- `&mut T`到`&T`
一个相似的转换时去掉一个[裸指针](#)的可变性:
- `*mut T`到`*const T`
引用也能被强转为裸指针:
- `&T`到`*const T`
- `&mut T`到`*mut T`
自定义强转可以用[`Deref`](#)定义。
强转是可传递的。
### `as`
`as`关键字进行安全的转换:
~~~
let x: i32 = 5;
let y = x as i64;
~~~
有三种形式的安全转换:显式转换,数字类型之间的转换,和指针转换。
转换并不是可传递的:即便是`e as U1 as U2`是一个有效的表达式,`e as U2`也不必要是(事实上只有在`U1`强转为`U2`时才有效)。
### 显式转换(Explicit coercions)
`e as U`是有效的仅当`e`是`T`类型而且`T`能强转为`U`。
### 数值转换
`e as U`的转换在如下情况下也是有效的:
- `e`是`T`类型而且`T`和`U`是任意数值类型:`numeric-cast`
- `e`是一个类 C 语言枚举(变量并没有附加值),而且`U`是一个整型:`enum-cast`
- `e`是`bool`或`char`而且`T`是一个整型:`prim-int-cast`
- `e`是`u8`而且`U`是`char`:`u8-char-cast`
例如:
~~~
let one = true as u8;
let at_sign = 64 as char;
let two_hundred = -56i8 as u8;
~~~
数值转换的语义是:
- 两个相同大小的整型之间(例如:`i32`->`u32`)的转换是一个`no-op`
- 从一个大的整型转换为一个小的整型(例如:`u32`->`u8`)会截断
- 从一个小的整型转换为一个大的整型(例如:`u8`->`u32`)会
- 如果源类型是无符号的会补零(zero-extend)
- 如果源类型是有符号的会符号(sign-extend)
- 从一个浮点转换为一个整型会向 0 舍入
- [注意:目前如果舍入的值并不能用目标整型表示的话会导致未定义行为(Undefined Behavior)](https://github.com/rust-lang/rust/issues/10184)。这包括 Inf 和 NaN。这是一个 bug 并会被修复。
- 从一个整型转换为一个浮点会产生整型的浮点表示,如有必要会舍入(未指定舍入策略)
- 从 f32 转换为 f64 是完美无缺的
- 从 f64 转换为 f32 会产生最接近的可能值(未指定舍入策略)
- [注意:目前如果值是有限的不过大于或小于 f32 所能表示的最大最小值会导致未定义行为(Undefined Behavior)](https://github.com/rust-lang/rust/issues/10184)。这是一个 bug 并会被修复。
### 指针转换
你也许会惊讶,[裸指针](#)与整型之间的转换是安全的,而且不同类型的指针之间的转换遵循一些限制。只有解引用指针是不安全的:
~~~
let a = 300 as *const char; // a pointer to location 300
let b = a as u32;
~~~
`e as U`在如下情况是一个有效的指针转换:
- `e`是`*T`类型,`U`是`*U_0`类型,且要么`U_0: Sized`要么`unsize_kind(T) == unsize_kind(U_0)`:`ptr-ptr-cast`
- `e`是`*T`类型且`U`是数值类型,同时`T: Sized`:`ptr-addr-cast`
- `e`是一个整型且`U`是`*U_0`类型,同时`U_0: Sized`:`addr-ptr-cast`
- `e`是`&[T; n]`类型且`U`是`*const T`类型:`array-ptr-cast`
- `e`是函数指针且`U`是`*T`类型,同时`T: Sized`:`fptr-ptr-cast`
- `e`是函数指针且`U`是一个整型:`fptr-addr-cast`
### `transmute`
`as`只允许安全的转换,并会拒绝例如尝试将 4 个字节转换为一个`u32`:
~~~
let a = [0u8, 0u8, 0u8, 0u8];
let b = a as u32; // four eights makes 32
~~~
这个错误为:
~~~
error: non-scalar cast: `[u8; 4]` as `u32`
let b = a as u32; // four eights makes 32
^~~~~~~~
~~~
这是一个“非标量转换(non-scalar cast)”因为这里我们有多个值:四个元素的数组。这种类型的转换是非常危险的,因为他们假设多种底层结构的实现方式。为此,我们需要一些更危险的东西。
`transmute`函数由[编译器固有功能](#)提供,它做的工作非常简单,不过非常可怕。它告诉Rust对待一个类型的值就像它是另一个类型一样。它这样做并不管类型检查系统,并完全信任你。
在我们之前的例子中,我们知道一个有4个`u8`的数组可以正常代表一个`u32`,并且我们想要进行转换。使用`transmute`而不是`as`,Rust允许我们:
~~~
use std::mem;
unsafe {
let a = [0u8, 0u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u32>(a);
}
~~~
为了使它编译通过我们要把这些操作封装到一个`unsafe`块中。技术上讲,只有`mem::transmute`调用自身需要位于块中,不过在这个情况下包含所有相关的内容是有好处的,这样你就知道该看哪了。在这例子中,`a`的细节也是重要的,所以它们放到了块中。你会看到各种风格的代码,有时上下文离得太远,因此在`unsafe`中包含所有的代码并不是一个好主意。
虽然`transmute`做了非常少的检查,至少它确保了这些类型是相同大小的,这个错误:
~~~
use std::mem;
unsafe {
let a = [0u8, 0u8, 0u8, 0u8];
let b = mem::transmute::<[u8; 4], u64>(a);
}
~~~
和:
~~~
error: transmute called with differently sized types: [u8; 4] (32 bits) to u64
(64 bits)
~~~
除了这些,你可以自行随意转换,只能帮你这么多了!
- 前言
- 贡献者
- 1.介绍
- 2.准备
- 3.学习 Rust
- 3.1.猜猜看
- 3.2.哲学家就餐问题
- 3.3.其它语言中的 Rust
- 4.语法和语义
- 4.1.变量绑定
- 4.2.函数
- 4.3.原生类型
- 4.4.注释
- 4.5.If语句
- 4.6.循环
- 4.7.所有权
- 4.8.引用和借用
- 4.9.生命周期
- 4.10.可变性
- 4.11.结构体
- 4.12.枚举
- 4.13.匹配
- 4.14.模式
- 4.15.方法语法
- 4.16.Vectors
- 4.17.字符串
- 4.18.泛型
- 4.19.Traits
- 4.20.Drop
- 4.21.if let
- 4.22.trait 对象
- 4.23.闭包
- 4.24.通用函数调用语法
- 4.25.crate 和模块
- 4.26.const和static
- 4.27.属性
- 4.28.type别名
- 4.29.类型转换
- 4.30.关联类型
- 4.31.不定长类型
- 4.32.运算符和重载
- 4.33.Deref强制多态
- 4.34.宏
- 4.35.裸指针
- 4.36.不安全代码
- 5.高效 Rust
- 5.1.栈和堆
- 5.2.测试
- 5.3.条件编译
- 5.4.文档
- 5.5.迭代器
- 5.6.并发
- 5.7.错误处理
- 5.8.选择你的保证
- 5.9.外部函数接口
- 5.10.Borrow 和 AsRef
- 5.11.发布途径
- 5.12.不使用标准库
- 6.Rust 开发版
- 6.1.编译器插件
- 6.2.内联汇编
- 6.4.固有功能
- 6.5.语言项
- 6.6.链接进阶
- 6.7.基准测试
- 6.8.装箱语法和模式
- 6.9.切片模式
- 6.10.关联常量
- 6.11.自定义内存分配器
- 7.词汇表
- 8.语法索引
- 9.参考文献
- 附录:名词中英文对照