【问题标题】:Why does the Rust borrow checker reject this function?为什么 Rust 借用检查器会拒绝这个功能?
【发布时间】:2014-11-01 08:56:26
【问题描述】:

这个(很傻的)函数编译失败:

fn silliness(mut z: &mut int) {
    z = &mut *z;
}

编译器输出:

$ rustc blah.rs 
blah.rs:2:5: 2:16 error: cannot assign to `z` because it is borrowed
blah.rs:2     z = &mut *z;
              ^~~~~~~~~~~
blah.rs:2:14: 2:16 note: borrow of `z` occurs here
blah.rs:2     z = &mut *z;
                       ^~
error: aborting due to previous error

在我看来,由于在任何时候都只有一个引用 z 指向的内容,所以应该没问题。什么不明白?

【问题讨论】:

    标签: rust


    【解决方案1】:

    它是安全的,但编译器还不够聪明,无法理解它。以下扰动编译良好:

    fn silliness(mut z: &mut int) {
        let tmp = z;
        z = &mut *tmp;
    }
    
    fn main() {}
    

    playpen

    这种引入临时技巧是一个有用的工具,尤其是在编写遍历您有 &mut 引用的数据结构的循环时,例如TreeMap 将它(let temp)用于find_mut,它使用循环来提高效率(而不是通过递归的明显实现,它不需要这个技巧)。

    【讨论】:

    • 我不认为这是因为编译器不够聪明。 &mut *z 必须 让编译器认为 z 是唯一借用的,因为这是防止混叠的唯一方法。否则,您将对同一内存位置有两个可用且可变的引用:原始的z&mut *z 的结果。这可以被认为是“好的”的唯一原因是这种混叠只存在很短的时间。但就我而言,即使是这么短的时间也太长了,不应该让编译器开发人员想出特殊的规则来检查短时别名的清白。
    • @sellibitze,它不够聪明:#10520。编译器可以很好地理解重新分配z 就像拥有临时的(即好像z 在重新分配之前被“移出”)。
    • (别名经常发生,而且很好:指针值可以相同——即机器级别的别名——只要只有一个路径可用,即是编译器强制执行的。)
    猜你喜欢
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 2018-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多