Transmutes
类型系统,让开!我们就算冒死也要重新解释这些位!尽管本书内容都关于不安全操作,我仍必须强烈强调,你应该深入思考,去寻找本节涵盖操作之外的其他方式。这确实是你在 Rust 中能做的最糟糕、最不安全的事情。这里的保护措施如同牙线般脆弱。
mem::transmute<T, U> 接收一个类型为 T 的值,并将其重新解释为类型 U。唯一的限制是 T 和 U 被验证具有相同的大小。用它造成未定义行为的方式令人难以置信。
-
首先,也是最重要的,创建一个处于无效状态的任何类型的实例都会导致无法预测的任意混乱。不要将
3位重塑(transmute)为bool。即使你从未对这个bool做过任何事情。就是不要。 -
Transmute 具有一个重载的返回类型。如果你不指定返回类型,它可能会产生一个令人惊讶的类型以满足类型推断。
-
将
&位重塑为&mut是未定义行为。尽管某些用法可能看似安全,但请注意,Rust 优化器可以自由地假定共享引用在其生命周期内不会改变,因此这样的位重塑将与这些假定相冲突。- 将
&位重塑为&mut总是未定义行为。 - 不,你不能这样做。
- 不,你也不特殊。
- 将
-
在没有显式提供生命周期的情况下,将类型位重塑(transmuting)为引用会产生一个无界生命周期。
-
当在不同的复合类型之间进行位重塑时,你必须确保它们的内存布局方式相同!如果布局不同,错误的字段就会被填充错误的数据,这会让你不开心,并且也可能导致未定义行为(参见上文)。
那么,你如何知道布局是否相同呢?对于
repr(C)类型和repr(transparent)类型,内存布局是精确定义的。但对于普通的repr(Rust)类型,则不是。即使是同一泛型类型的不同实例,其内存布局也可能截然不同。Vec<i32>和Vec<u32>的字段可能顺序相同,也可能不同。关于数据布局具体保证了什么、没有保证什么,其细节仍在 UCG WG 中讨论确定。
mem::transmute_copy<T, U> 不知为何比这甚至更不安全。它从一个 &T 中复制 size_of<U> 个字节,并将它们解释为一个 U。mem::transmute 具有的大小检查消失了(因为复制前缀可能是有效的),尽管 U 比 T 大是未定义行为。
当然,你也可以使用裸指针转换或 unions 来实现这些函数的所有功能,但没有任何 Lints 或其他基本健全性检查。裸指针转换和 unions 不会神奇地避免上述规则。