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
FFIDrop标志
前一章的例子涉及到Rust的一个有趣的问题。我们看到我们可以安全地为一段内存初始化、反初始化、再初始化。对于Copy类型,这一点不是很重要,因为数据不过是一堆字节而已。但是对于有析构函数的类型就是另外一回事了:变量每次被赋值或者离开作用域的时候,Rust都需要判断是否要调用析构函数。在有条件地初始化的情况下,Rust是如何做到这一点的呢?
注意,不是所有的赋值操作都需要考虑这一点。通过解引用赋值是一定会触发析构函数,而使用let赋值则一定不会触发:
let mut x = Box::new(0); // let创建一个全新的变量,所以一定不会调用drop let y = &mut x; *y = Box::new(1); // 解引用假设被引用变量是初始化过的,所以一定会调用drop
只有当覆盖一个已经初始化的变量或者变量的一个子成员时,才需要考虑这个问题。
Rust实际上是在运行期判断是否销毁变量。当一个变量被初始化和反初始化时,变量会更新它的”drop标志“的状态。通过解析这个标志的值,判断变量是否真的需要执行drop。
当然,大多数情况下,在编译期就可以知道一个值在每一点的初始化状态。符合这一点的话,编译器理论上可以生成更有效率的代码!比如,无分支的程序有着如下的静态drop语义:
let mut x = Box::new(0); // x未初始化;仅覆盖值
let mut y = x; // y未初始化;仅覆盖值,并设置x为未初始化
x = Box::new(0); // x未初始化;仅覆盖值
y = x; // y已初始化;销毁y,覆盖它的值,设置x为未初始化
// y离开作用域;y已初始化;销毁y
// x离开作用域;x未初始化;什么都不用做
类似的,有分支的代码当所有分支中的初始化行为一致的时候,也可以有静态的drop语义:
let mut x = Box::new(0); // x未初始化;仅覆盖值
if condition {
drop(x); // x失去值;设置x为未初始化
} else {
printn!("{}", x);
drop(x); // x失去值;设置x为未初始化
}
x = Box::new(0); // x未初始化;仅覆盖值
// x离开作用域;x已初始化;销毁x
但是,下面的代码则需要运行时信息以正确执行drop:
let x;
if condition {
x = Box::new(0); // x未初始化;仅覆盖值
println!("{}", x);
}
// x离开作用域;x可能未初始化
// 检查drop标志
当然,修改为下面的代码就又可以得到静态drop语义:
if condition {
let x = Box::new(0);
println!("{}", x);
}
drop标志储存在栈中,并不在实现Drop的类型里。
下一章:Rust 非安全方式
非安全方式:一个特殊情况是数组。安全Rust不允许部分地初始化数组,初始化一个数组时,你可以通过let x = [val; N]为每一个位置赋予相同的值,或者是单独指定每一个成员的值let x = [val1, val2, val3]。很多 ...
AI 中文社