Rust 安全代码
安全与非安全代码对比 安全与非安全代码交互 非安全Rust能做什么 编写非安全代码数据布局
repr(Rust) 类型中的奇行种 可选的数据表达方式所有权
所有权 引用 别名 生命周期 生命周期的局限 省略生命周期 无界生命周期 高阶trait边界 子类型和变性 Drop检查 幽灵数据 分解借用类型转换
类型转换 强制类型转换 点操作符 显式类型转换 变形未初始化内存
未初始化内存 安全方式 Drop标志 非安全方式资源管理
基于所有权的资源管理 构造函数 析构函数 泄露展开
展开 异常安全性 污染并发
并发 竞争 Send和Sync 原子操作实现 Vec
实现 Vec 布局 内存分配 push和pop 回收资源 DeRef 插入和删除 IntoIter RawVec Drain 处理零尺寸类型 最终代码FFI
FFIRust 安全代码
安全与非安全代码对比 安全与非安全代码交互 非安全Rust能做什么 编写非安全代码数据布局
repr(Rust) 类型中的奇行种 可选的数据表达方式所有权
所有权 引用 别名 生命周期 生命周期的局限 省略生命周期 无界生命周期 高阶trait边界 子类型和变性 Drop检查 幽灵数据 分解借用类型转换
类型转换 强制类型转换 点操作符 显式类型转换 变形未初始化内存
未初始化内存 安全方式 Drop标志 非安全方式资源管理
基于所有权的资源管理 构造函数 析构函数 泄露展开
展开 异常安全性 污染并发
并发 竞争 Send和Sync 原子操作实现 Vec
实现 Vec 布局 内存分配 push和pop 回收资源 DeRef 插入和删除 IntoIter RawVec Drain 处理零尺寸类型 最终代码FFI
FFIRust 显式类型转换
显式类型转换是强制类型转换的超集:所有的强制类型转换都可以通过显式转换的方式主动触发。但有一些场景只适用于显式转换。强制类型转换很普遍而且通常无害,但是显式类型转换是一种“真正的转换“,它的应用就很稀少了,而且有潜在的危险。因此,显式转换必须通过关键字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 integerinteger as *Tnumber as number- 无成员枚举
as integer bool as integerchar as integeru8 as char&[T; n] as *const Tfn as *T,其中T: Sizedfn 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)
- 如果源类型是无符号的,将会补零
- 如果源类型是有符号的,将会有符号补零
- 浮点类型转换为整型会舍去浮点部分
- 注意:如果目标整数类型不能表示舍入的结果,...。包括Inf和NaN。这是一个bug,会在后续版本中修复。
- 整型转换为浮点类型会产生这个整型的浮点型表示,
- f32转换为f64可以无损失地完美转换,必要的时候做舍入(舍入到最近的可能取值,距离相同的取偶数)
- f64转换为f32会生成最近可能值(舍入到最近的可能取值,距离相同的取偶数)
下一章:Rust 变形
类型系统你给我滚开!我要自己解析这些字节,不成功便成仁!虽然本书都是关于非安全的内容,我还是希望你能仔细考虑避免使用本章讲到的内容。这是你在Rust中所能做到的真真正正、彻彻底底、最最可怕的非安全行为。所有的保护机制都形同虚 ...
AI 中文社