【问题标题】:Pushing something into a vector depending on its last element根据最后一个元素将某些东西推入向量
【发布时间】:2015-10-27 03:22:14
【问题描述】:

我想获取向量的最后一个元素,并用它来确定下一个要推入的元素。这是一个不起作用的示例,但它显示了我想要实现的目标:

let mut vector: Vec<i32> = Vec::new();

if let Some(last_value) = vector.last() {
    vector.push(*last_value + 1);
}

我不能使用push,而向量也是不可变借用的:

error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:9
  |
4 |     if let Some(last_value) = vector.last() {
  |                               ------ immutable borrow occurs here
5 |         vector.push(*last_value + 1);
  |         ^^^^^^ mutable borrow occurs here
6 |     }
  |     - immutable borrow ends here

什么是这样做的好方法?

【问题讨论】:

    标签: rust borrow-checker


    【解决方案1】:

    在非词法生命周期之后

    您的原始代码works as-is in Rust 2018,启用non-lexical-lifetimes

    fn main() {
        let mut vector: Vec<i32> = Vec::new();
    
        if let Some(last_value) = vector.last() {
            vector.push(*last_value + 1);
        }
    }
    

    借用检查器已得到改进,以实现last_value 中的引用与推入新值所需的vector 的可变借用不重叠。

    请参阅Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in? 以了解借用检查器还不够智能以处理的类似情况(从 Rust 1.32 开始)。

    在非词法生命周期之前

    vector.last() 的结果是Option&lt;&amp;i32&gt;。该值中的引用保留了借用的向量。我们需要先删除对向量的所有引用,然后才能推送到它。

    如果您的向量包含Copyable 值,请将值从向量中复制出来以更快地结束借用。

    fn main() {
        let mut vector: Vec<i32> = Vec::new();
    
        if let Some(&last_value) = vector.last() {
            vector.push(last_value + 1);
        }
    }
    

    在这里,我使用了Some(&amp;last_value) 模式,而不是Some(last_value)。这解构引用并强制复制。如果您尝试使用不是 Copyable 的类型使用此模式,您将收到编译器错误:

    error[E0507]: cannot move out of borrowed content
     --> src/main.rs:4:17
      |
    4 |     if let Some(&last_value) = vector.last() {
      |                 ^----------
      |                 ||
      |                 |hint: to prevent move, use `ref last_value` or `ref mut last_value`
      |                 cannot move out of borrowed content
    

    如果您的向量不包含 Copyable 类型,您可能需要先克隆该值:

    fn main() {
        let mut vector: Vec<String> = Vec::new();
    
        if let Some(last_value) = vector.last().cloned() {
            vector.push(last_value + "abc");
        }
    }
    

    或者您可以以另一种方式转换该值,以便 .map() 调用返回一个不从向量借用的值。

    fn main() {
        let mut vector: Vec<String> = Vec::new();
    
        if let Some(last_value) = vector.last().map(|v| v.len().to_string()) {
            vector.push(last_value);
        }
    }
    

    【讨论】:

    • 你能解释一下你的第一个例子与 OP 的代码相比吗?它到底有什么不同? Copy 在这里发挥了怎样的作用?
    • @JimmyCuadra 在 OP 的代码中,last_value()last_value 匹配。由于last_value() 返回一个引用,last_value 也成为一个引用。但是,Francis 将模式更改为&amp;last_value,因此引用匹配&amp;,而值本身匹配last_value,因此按值复制。这称为解构。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    相关资源
    最近更新 更多