5.30.类型转换

最后更新于:2022-04-01 00:44:33

Rust,和它对安全的关注,提供了两种不同的在不同类型间转换的方式。第一个,`as`,用于安全转换。相反,`transmute`允许任意的转换,而这是Rust中最危险的功能之一! ## `as` `as`关键字进行了基本的转换: ~~~ let x: i32 = 5; let y = x as i64; ~~~ 然而,它只允许特定类型的转换: ~~~ 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 ^~~~~~~~ ~~~ 它是一个“混合类型转换”因为这里我们有多个值:数组的4个元素。这种类型的转换灰常危险,因为它们假设了多个底层结构的实现方式。为此,我们需要一些更危险的东西。 ## `transmute` `transmute`函数由[编译器固有功能](http://doc.rust-lang.org/nightly/book/intrinsics.html)提供,它做的工作非常简单,不过非常可怕。它告诉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 on types with different sizes: [u8; 4] (32 bits) to u64 (64 bits) ~~~ 除了这些,你可以自行转换!
';