我想做什么:
enum Test {
Value1,
Value2,
Value3
}
fn main() {
let mut test_vec: Vec<Test> = Vec::new();
test_vec.push(Test::Value2);
if let Some(last) = test_vec.last() {
test_vec.push(*last);
}
//Wanted output: vector with [Test::Value2, Test::Value2]
}
Run Code Online (Sandbox Code Playgroud)
我明白,当我打电话时last(),它会返回Option<&Test>
所以它会借用test_vec直到if-let块结束.
我尝试了以下但没有成功:
if let Some(last) = test_vec.last().map(|v| v.clone()) {
test_vec.push(*last);
}
//and
let last = test_vec.last().unwrap().clone();
test_vec.push(*last);
Run Code Online (Sandbox Code Playgroud)
当试图找出借用检查器抱怨的原因时,识别所涉及的类型会很有用。
如果你输入:
let _: () = test_vec.last().map(|v| v.clone());
Run Code Online (Sandbox Code Playgroud)
你得到一个错误,抱怨()和core::option::Option<&Test>是不是同一类型。
这是怎么回事?非常简单地说,如果你克隆 an&Test你会得到 an &Test,因此调用.map(|v| v.clone())aOption<&Test>会得到一个Option<&Test>。显然,它仍然在借钱。
如果您输入:
let _: () = test_vec.last().unwrap().clone();
Run Code Online (Sandbox Code Playgroud)
你得到一个错误,抱怨()和&Test是不是同一类型。
通过调用unwrapanOption<&Test>你会得到一个&Test然后被克隆到一个&Test.
所以,问题是缺乏解引用。您需要提前取消引用,以避免借贷test_vec在Some(last):
if let Some(last) = test_vec.last().map(|v| (*v).clone()) {
test_vec.push(last);
}
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,因为Test没有实现clone。一旦修复(通过#[derive(Clone)]),它就会编译。
由于从引用克隆是一种常见的需求,因此在Option(和Iterator)上有一个专用方法,称为cloned:
if let Some(last) = test_vec.last().cloned() {
test_vec.push(last);
}
Run Code Online (Sandbox Code Playgroud)
要解决借用问题,你可以调用Option::cloned,从而产生Option<T>a Option<&T>.要做到这一点,Test必须实施Clone.您可以实现Clone的Test使用derive:
// To allow assert_eq, we also derive Debug and PartialEq
#[derive(Debug, PartialEq, Clone)]
enum Test {
Value1,
Value2,
Value3
}
fn main() {
let mut test_vec = Vec::new();
test_vec.push(Test::Value2);
if let Some(last) = test_vec.last().cloned() {
test_vec.push(last);
}
assert_eq!(vec![Test::Value2, Test::Value2], test_vec);
}
Run Code Online (Sandbox Code Playgroud)