Rust编译器如何知道值是否已移动?

Rust编译器如何知道值是否已移动?,rust,Rust,一个简单的例子: struct A; fn main() { test(2); test(1); } fn test(i: i32) { println!("test"); let a = A; if i == 2 { us(a); } println!("end"); } impl Drop for A { fn drop(&mut self) { println!("drop");

一个简单的例子:

struct A;

fn main() {
    test(2);
    test(1);
}

fn test(i: i32) {
    println!("test");
    let a = A;
    if i == 2 {
        us(a);
    }
    println!("end");
}

impl Drop for A {
    fn drop(&mut self) {
        println!("drop");
    }
}

#[allow(unused_variables)]
fn us(a: A){
    println!("use");
}
当我运行它时,输出是:

test
use
drop
end
test
end
drop
我知道在
test(2)
案例中,
a
被移动到
us(a)
,所以它的输出是“test-use-drop-end”

但是,在
test(1)
中,输出是“testend drop”,这意味着编译器知道
a
没有移动

如果调用了
us(a)
,则无需在
test(i)
中删除
a
,它将在
us(a)
中删除;如果未调用
us(a)
,则必须在
println之后删除
a
!(“结束”)

既然编译器不可能知道是否调用了
us(a)
,那么编译器如何知道在
println之后是否应该调用
a.drop()
!(“结束”)

中对此进行了解释:

从Rust 1.0开始,drop标志实际上并没有秘密地隐藏在实现drop的任何类型的隐藏字段中

隐藏字段说明当前值是否已删除,如果未删除,则为删除。因此,这在运行时是已知的,并且需要一些簿记


展望未来,有一个RFC

RFC的理念是通过以下方式替换隐藏字段:

  • 识别无条件丢弃(不需要任何运行时检查)
  • 在堆栈上的函数框中,为有条件删除的值隐藏一个隐藏字段
  • 与旧策略相比,新策略有几个优点:

    • 主要优点是
      #[repr(C)]
      现在将始终提供与C的表示等价的表示,即使
      struct
      实现了
      Drop
    • 另一个重要的优点是节省内存(通过不膨胀
      struct
      大小)
    • 另一个微小的优势是,由于无条件丢弃和更好的缓存(通过减少内存大小),可能会略微提高速度