英文:
Why Drop trait is only executed at the end of the scope, instead of after the last use?
问题
这是来自rust onomicon # lifetime的问题。
第一个例子可以编译,因为x是一个引用,编译器可以推断其生命周期最小到最后的使用位置:println!()
,因此x在此行之后被丢弃。
但是当x是实现了Drop特性的结构体时情况就不同了。
在这种情况下,drop()
仅在作用域的最末尾执行,因此x保持有效直到最后一行。
但是为什么编译器不能将x的生命周期最小化到最后的使用?当x实现了Drop特性时,是否在最后的使用后立即应用drop()
会产生一些非平凡的副作用?
英文:
This is a question from rust onomicon # lifetime
The first example can compile, as x is a reference and the compiler can infer its lifetime as minimal as the last use here :println!()
, so x is dropped after this line.
let mut data = vec![1, 2, 3];
let x = &data[0];
println!("{}", x);
// This is OK, x is no longer needed
data.push(4);
But the case is different when x is a struct implemented Drop trait.
#[derive(Debug)]
struct X<'a>(&'a i32);
impl Drop for X<'_> {
fn drop(&mut self) {}
}
let mut data = vec![1, 2, 3];
let x = X(&data[0]);
println!("{:?}", x);
data.push(4);
// Here, the destructor is run and therefore this'll fail to compile.
The onomicon says in this case, drop()
is only executed at the very end of a scope, so x keeps valid until the last line.
But why the compiler cannot minimize the lifetime of x to the last use? And is applying drop()
just after the last use has some nontrivial side effects when x is implemented Drop trait?
答案1
得分: 3
主要原因是它曾经被定义为这样,现在不能再改变了,因为这样做不再可能是向后兼容的,可能会破坏一些东西。
您的代码可以通过引入嵌套作用域来轻松修复,这在我看来是这些情况下的最佳实践:
#[derive(Debug)]
struct X<'a>(&'a i32);
impl Drop for X<'_> {
fn drop(&mut self) {}
}
fn main() {
let mut data = vec![1, 2, 3];
{
let x = X(&data[0]);
println!("{:?}", x);
}
data.push(4);
}
X(1)
或者,您可以手动drop
它:
#[derive(Debug)]
struct X<'a>(&'a i32);
impl Drop for X<'_> {
fn drop(&mut self) {}
}
fn main() {
let mut data = vec![1, 2, 3];
let x = X(&data[0]);
println!("{:?}", x);
drop(x);
data.push(4);
}
X(1)
英文:
The primary reason is that it was once defined to be like that, and now changing it isn't possible any more because it wouldn't be backwards-compatible and might break stuff.
Your code is easily fixable by introducing a nested scope, though, which is (to my understanding) best practice in those situations:
#[derive(Debug)]
struct X<'a>(&'a i32);
impl Drop for X<'_> {
fn drop(&mut self) {}
}
fn main() {
let mut data = vec![1, 2, 3];
{
let x = X(&data[0]);
println!("{:?}", x);
}
data.push(4);
}
X(1)
Alternatively, you could drop
it manually:
#[derive(Debug)]
struct X<'a>(&'a i32);
impl Drop for X<'_> {
fn drop(&mut self) {}
}
fn main() {
let mut data = vec![1, 2, 3];
let x = X(&data[0]);
println!("{:?}", x);
drop(x);
data.push(4);
}
X(1)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论