【问题标题】:How does the Rust compiler know whether a value has been moved or not?Rust 编译器如何知道一个值是否被移动了?
【发布时间】:2016-01-14 08:18:47
【问题描述】:

一个简单的例子:

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) 中,输出是“test-end-drop”,这意味着编译器知道a 没有被移动。

如果调用us(a),则a不需要在test(i)中删除,它会在us(a)中删除;如果没有调用us(a),则必须在println!("end") 之后删除a

既然编译器不可能知道us(a)是否被调用,那么编译器如何知道a.drop()println!("end")之后是否应该被调用?

【问题讨论】:

    标签: rust


    【解决方案1】:

    这在Rustnomicon中有解释:

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

    隐藏字段告诉当前值是否已被删除,如果没有,则它是。因此,这在运行时是已知的,并且需要一些记录。


    展望未来,remove these hidden fields 有一个 RFC。

    RFC 的想法是将隐藏字段替换为:

    1. 识别无条件丢弃(不需要任何运行时检查)
    2. 在函数框架中的 堆栈 上存储一个隐藏字段,用于那些有条件地被丢弃的值

    与旧策略相比,这种新策略有几个优点:

    • 主要优点是 #[repr(C)] 现在总是给出与 C 相同的表示,即使 struct 实现 Drop
    • 另一个重要优势是节省内存(通过不增加 struct 大小)
    • 另一个轻微的优势是,由于无条件丢弃和更好的缓存(通过减少内存大小),可能会略微提高速度

    【讨论】:

      猜你喜欢
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 1970-01-01
      • 2014-08-09
      • 2010-11-30
      • 1970-01-01
      • 2014-10-04
      相关资源
      最近更新 更多