非词法生命周期之后
您的原始代码可以在启用非词法生命周期的Rust 2018中直接使用:
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中(截至目前)借用检查器尚不能很好地处理它。
Non-Lexical Lifetimes之前
vector.last()
的结果为Option<&i32>
。该值中的引用会使向量被借用。我们需要在向量上推入元素之前摆脱向量中的所有引用。
如果您的向量包含可Copy
的值,请将该值从向量中复制出来以更快地结束borrow。
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);
}
}
last_value()
与last_value
匹配。由于last_value()
返回一个引用,因此last_value
也成为了一个引用。然而,Francis 将模式更改为&last_value
,因此引用匹配了&
,而值本身则匹配了last_value
,因此被按值复制。这被称为解构。 - Malcolm