根据最后一个元素将某些东西推入向量

时间:2015-10-27 03:22:15

标签: rust borrow-checker

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

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

这样做的好方法是什么?

1 个答案:

答案 0 :(得分:8)

非词汇生命期后

原始代码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<&i32>。该值中的引用保持向量借用。在我们推进之前,我们需要摆脱对向量的所有引用。

如果您的向量包含Copy个值,请将该值复制出向量,以便更快地结束借用。

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

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

在这里,我使用了模式Some(&last_value)而不是Some(last_value)。此解构引用并强制复制。如果您尝试使用不具有Copy类型的此模式,则会出现编译器错误:

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

如果您的向量不包含Copy种类型,您可能希望首先克隆该值:

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);
    }
}