I'm trying to write code that gets the last element of some vector and do different actions (including mutation of the vector) depending on that element.
I tried like this:
#[derive(Clone, PartialEq)]
enum ParseItem {
Start,
End,
}
let mut item_vec = vec![ParseItem::End];
loop {
let last_item = *item_vec.last().clone().unwrap();
match last_item {
ParseItem::End => item_vec.push(ParseItem::Start),
_ => break,
}
}
And I get the following error:
error: cannot move out of borrowed content
let last_item = *item_vec.last().clone().unwrap();
I thought by cloning item_vec.last()
, the problems with ownership would be solved, but it seems not.
If I try the same thing with a vector of integers like this:
let mut int_vec = vec![0];
loop {
let last_int = *int_vec.last().clone().unwrap();
match last_int {
0 => int_vec.push(1),
_ => break,
}
}
the compiler doesn't complain about borrowing.
Why does my code fails to compile?
item_vec.last()
is an Option<&T>
.
item_vec.last().clone()
is another Option<&T>
. This actually performs a shallow copy of the reference. This means you haven't actually fixed anything!
Intuitively, this makes sense - cloning a pointer can return a value type to store directly on the stack, but a clone of an Option<&T>
can't clone the T
because it has nowhere to put it.
This works because an Option<T>
actually calls clone
on an &T
, so Option<&T>
calls clone
on an &&T
, which means the &self
parameter in the trait resolves to self = &T
. This means we use the impl
of Clone
for &T
:
impl<'a, T: ?Sized> Clone for &'a T {
/// Returns a shallow copy of the reference.
#[inline]
fn clone(&self) -> &'a T { *self }
}
*item_vec.last().clone().unwrap()
thus is still a borrow of the vector.
One can fix this in two basic ways. One is to use Option
's cloned
method, which clones the inner reference away:
item_vec.last().cloned().unwrap()
This is implemented as a map
on the internal data:
impl<'a, T: Clone> Option<&'a T> {
/// Maps an Option<&T> to an Option<T> by cloning the contents of the Option.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn cloned(self) -> Option<T> {
self.map(|t| t.clone())
}
}
The other option is to unwrap
and only then clone
the reference, to get a value out:
item_vec.last().unwrap().clone()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With