Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.7k views
in Technique[技术] by (71.8m points)

rust - How to clone last element from vector?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...