【问题标题】:How to satisfy Rust borrow checker with this simple code?如何用这个简单的代码满足 Rust 借用检查器?
【发布时间】:2017-07-27 07:29:29
【问题描述】:

我从借用检查器中得到一个 Rust 编译错误,不知道如何修复它。
下面的代码很简单,C++中类似的代码没有问题。

fn main() {
    let mut nums = vec![1, 2, 3];
    if let Some(x) = nums.last() {
        nums.push(*x);
    }
}

这里是错误:

message: 'cannot borrow `nums` as mutable because it is also borrowed as immutable (4, 9)'

【问题讨论】:

  • 不了解 Rust,它可能不喜欢在与 nums.push() 相同的语句中执行 nums.last(),因为在将新条目推送到 nums 时 nums.last() 的值可能会发生变化.

标签: rust


【解决方案1】:

当您调用.last() 时,您将nums 借用为不可变的,因为变异会使您持有的引用x 无效。然后调用.push,它借用nums 作为可变的。

问题是你现在有一个相同值的不可变借用和一个可变借用,这违反了 rusts 内存安全保证(多个读取器单个写入器保证你会永远不会有任何地方的无效内存)。

fn main() {
    let mut nums = vec![1, 2, 3];
    if let Some(x) = nums.last() { // Immutable borrow starts here
        nums.push(*x);             // Mutable borrow starts here
    }                              // Immutable and mutable borrows end here
}

根据@DanielSanchez 的示例,解决方案是通过立即删除其结果的引用来降低不可变借用的范围:

let mut nums = vec![1, 2, 3];
if let Some(&x) = nums.last() { // Immutable borrow starts and ends here
    nums.push(x);               // Mutable borrow starts here
}                               // Mutable borrow ends here

【讨论】:

  • 谢谢,这个答案更清楚了。我只是不知道为什么不可变借用的生命没有结束。现在我知道原因是 nums.last() 的返回值是引用。但是为什么 "&x" 可以结束 Immutable 借用呢?
  • 在这种情况下,&x 实际上取消了对x 的引用。通常,这会移动x,但整数实现Copy 特征,这意味着我们使用自动生成的x 副本而不是移动x。我们取消引用x 会破坏.last() 返回的引用并结束它引起的借用。
【解决方案2】:

您可以取消引用保护子句中的引用:

fn main() {
    let mut nums = vec![1, 2, 3];
    if let Some(&x) = nums.last() {
        nums.push(x);
    }
}

Rust 有一个强大的模式匹配功能,如果你知道它的类型,你几乎可以解压所有东西。检查Rust pattern matching documentation

【讨论】:

  • 谢谢,它有效。我认为 nums.last() 与 nums.push() 冲突。 Rust 文档在哪里详细解释了“参考解包”?
  • @LiLei,我更新了答案,你应该看看 rust 具有的所有模式匹配功能(甜如蜜);)
猜你喜欢
  • 1970-01-01
  • 2014-09-10
  • 2018-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多