What I am trying to do:
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]
}
I understand that when I call last()
, it will return Option<&Test>
So it will borrow the test_vec
till the end of the if-let block.
I tried the following without success:
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);
When trying to figure out why the borrow checker complains it can be useful to identify the types involved.
If you type out:
let _: () = test_vec.last().map(|v| v.clone());
you get an error complaining that ()
and core::option::Option<&Test>
are not the same type.
What's going on? Very simply put, if you clone an &Test
you get an &Test
, thus calling .map(|v| v.clone())
on a Option<&Test>
gives an Option<&Test>
. Obviously, it still borrows.
The same problem occurs with your next attempt, if you type out:
let _: () = test_vec.last().unwrap().clone();
you get an error complaining that ()
and &Test
are not the same type.
By calling unwrap
on an Option<&Test>
you get an &Test
which is then cloned into an &Test
.
So, the problem is a lack of dereferencing. You need to dereference earlier, to avoid borrowing test_vec
in Some(last)
:
if let Some(last) = test_vec.last().map(|v| (*v).clone()) {
test_vec.push(last);
}
of course, this does not work because Test
does not implement clone
. Once that is fixed (by #[derive(Clone)]
), it compiles.
Since cloning from references is such a common need, there is a dedicated method on Option
(and Iterator
) called cloned
:
if let Some(last) = test_vec.last().cloned() {
test_vec.push(last);
}
To solve the borrow problem you can call Option::cloned
, that produces a Option<T>
from a Option<&T>
. To do this, Test
must implement Clone
. You can implement Clone
for Test
using 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);
}