原文链接:https://doc.rust-lang.org/nomicon/casts.html
显式类型转换
显式类型转换是强制类型转换的超集:所有的强制类型转换都可以通过显式转换的方式主动触发。但有一些场景只适用于显式转换。强制类型转换很普遍而且通常无害,但是显式类型转换是一种“真正的转换“,它的应用就很稀少了,而且有潜在的危险。因此,显式转换必须通过关键字as
主动地触发:expr as Type
。
真正的转换一般是针对裸指针和基本数字类型的。虽然说过它们存在风险,但是在运行期却是很稳定的。如果类型转换操作触发了一些奇怪的边界场景,Rust并不会给出任何提示。转换仍然会被认为是成功的。这就要求显式类型转换必须在类型层面是合法的,否则会在编译期被拒绝。比如,7u8 as bool
不会编译成功。
也就是说,显式类型转换不属于非安全(unsafe)行为,因为仅凭转换操作是不会违背内存安全性的。比如,将整型转换为裸指针很容易导致可怕的后果。但是,创建一个指针这个行为本身是安全的,而真正使用裸指针的操作则必须被标为unsafe
。
以下是所有显式类型转换的情况。简单起见,我们用*
表示*const
或者*mut
,用integer
表示任意整数基本类型:
*T as *U
,其中T, U: Sized
*T as *U
,TODO:明确unsize的情况*T as integer
integer as *T
number as number
- 无成员枚举
as integer
bool as integer
char as integer
u8 as char
&[T; n] as *const T
fn as *T
,其中T: Sized
fn as integer
注意,裸slice转换后长度会改变,比如*const [u16] as *const [u8]
创建的slice只包含原本一半的内存。
显示类型转换不是可传递的,也就是说,即使e as U1 as U2
是合法的表达式,也不能认为e as U2
就一定是合法的。
对于数字类型的转换,如下几点需要注意:
- 相同大小的整型互相转换(比如i32->u32)是一个no-op
- 大尺寸的整型转换为小尺寸的整型(比如u32->u8)会被截断
- 小尺寸的整型转换为大尺寸的整型(比如u8->u32)
- 如果源类型是无符号的,将会补零
- 如果源类型是有符号的,将会有符号补零
- 浮点类型转换为整型会舍去浮点部分,并且当浮点数超出整数范围时会产生“饱和转换”
- 太大的浮点数会变成可能的最大整数
- 太小的浮点数会产生可能的最小整数
- NaN 产生零
- 整型转换为浮点类型会产生这个整型的浮点型表示,
- f32转换为f64可以无损失地完美转换,必要的时候做舍入(舍入到最近的可能取值,距离相同的取偶数)
- f64转换为f32会生成最近可能值(舍入到最近的可能取值,距离相同的取偶数)