在Rust中,局部变量(来自相同作用域)以与定义顺序相反的顺序删除.
fn test_foo(){
let s1:String = String::from("A");
let mut foo:Foo = Foo { data: & s1 };
let s2:String = String::from("B");
foo.data = & s2;
}
我们在这里按顺序声明三个局部变量:s1
、foo
和s2
.铁 rust 想要以相反的顺序丢弃它们:首先是s2
,然后是foo
,然后是s1
.然而,生命周期有一个问题.一旦go 掉s2
,那么foo.data
就是uninitialized,也就是说它指向垃圾内存.
现在,为什么没有Drop
也能行得通呢?铁 rust 有一个叫partial moves的概念.如果您的 struct 有多个字段,Rust将允许您移出某些字段,而不会使整个 struct 无效.原则上,如果我有一个
struct Person {
name: String,
age: i32,
occupation: String,
}
我做let name = my_person.name;
(其中my_person: Person
),然后我从Person
中移出一个值.因此,my_person.name
是无效的,在没有部分移动的情况下,Rust应该认为my_person
完全无效.但是,我们知道my_person.age
和my_person.occupation
仍然有效,所以拉斯特会让age
和occupation
留在原地.它记得name
被移动了(因此不应该被丢弃的垃圾),而age
和occupation
仍然有效.
在您的示例中,同样的事情正在发生.铁 rust 想要下跌s2
,但Foo
仍然提到它.Ruust认为这很好:我们将go 掉s2
,并简单地说Foo
已经是partially moved:它的data
字段不再有效.然后,当我们接下来删除foo
时,我们不需要删除引用,只需要删除最外面的Foo
层本身.
没有Drop
个实例,这是很好的,铁 rust 将允许它.但是,如果impl<'a> Drop for Foo<'a>
在作用域内,则Foo
的部分移动为completely disabled.Rust看到您正在实现一些定制的Drop
行为,现在它不允许部分初始化的对象存在,因为我们必须删除一个部分初始化的对象,并且Rust无法预测您的定制Drop
代码将做什么或它将做出什么假设.
因此,对于Drop
实现,Rust仍然希望首先删除s2
,但它不能将引用部分移出foo
,因为这会使foo
处于部分初始化状态,这是不允许的.