在 Rust 书 第 15 章第 3 节中提供了一个示例,以显示 Rust 何时对变量 c 和 d 运行 drop 函数。
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
}
输出为:
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
我的问题是为什么 rust 编译器会按这个顺序删除变量?鉴于变量没有被使用或引用,它们不应该在声明后立即删除,并按照声明的顺序删除吗?我还尝试了使用另一个声明的变量的相同代码。
//snip
let e = CustomSmartPointer {
data: String::from("more stuff"),
};
并且输出保持反转
CustomSmartPointers created.
Dropping CustomSmartPointer with data `more stuff`!
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
虽然变量被删除的方式让人想起数据是如何从堆栈中压入和弹出的,但这应该是一个转移注意力的事情。
鉴于变量未被使用或引用,不应该在声明后立即将其删除不。这种行为将使
RAII 变得不可能。例如这个:
let mut lock: Mutex<i32> = Mutex::new(1);
...
{
let mut guard = lock.lock().unwrap();
*guard += 1;
}
这里的guard
不仅在内部保存数据,更重要的是它是一个在drop时解锁底层锁的结构。由于在范围末尾发生了 drop,我自动锁定了整个范围。我不必记住手动解锁锁。如果范围包含例如 ifs,这将非常容易出错。
并按照宣布的顺序被删除?顺序是次要的,事实上任何顺序都可以。但必须做出一些选择,并且保持一致是有用的。所以这里只有两个自然的选择:与声明的顺序相同或相反。
相反的顺序更自然。例如回到带锁的例子。假设我们有两个:
{
let mut guard1 = lock1.lock().unwrap();
let mut guard2 = lock2.lock().unwrap();
// do something
}
您真的希望 lock1 在 lock2 之前解锁吗?我想大多数人都不会。