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

stf*_*fnp 6 rust borrow-checker

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

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

if let Some(last_value) = vector.last() {
    vector.push(*last_value + 1);
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这样做有什么好办法?

Fra*_*gné 8

在非词汇生命周期之后

您的原始代码在Rust 2018中按原样运行,可以实现非词法生命周期:

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

    if let Some(last_value) = vector.last() {
        vector.push(*last_value + 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

借用检查器已得到改进,意识到引用last_value不会与vector推动新值所需的可变借用重叠.

请参阅从HashMap或Vec返回引用导致借用超出其范围?对于类似的情况,借用检查器还不够聪明,无法处理(从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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我使用的是模式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
Run Code Online (Sandbox Code Playgroud)

如果向量不包含Copy可用类型,则可能需要首先克隆该值:

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

    if let Some(last_value) = vector.last().cloned() {
        vector.push(last_value + "abc");
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以以另一种方式转换值,以便.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);
    }
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

985 次

最近记录:

7 年,7 月 前