如何克隆向量中的最后一个元素?

5
我正在尝试编写代码,以获取一些向量的最后一个元素,并根据该元素执行不同的操作(包括对向量的变异)。
我尝试了以下代码:
#[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,
    }
}

我遇到了以下错误:

错误:无法移动借用的内容
let last_item = *item_vec.last().clone().unwrap();

我原以为通过克隆item_vec.last(),可以解决所有权问题,但似乎并不是这样。

如果我尝试对一个整数向量做同样的操作,如下所示:

let mut int_vec = vec![0];
loop {
    let last_int = *int_vec.last().clone().unwrap();
    match last_int {
        0 => int_vec.push(1),
        _ => break,
    }
}

编译器没有抱怨借用。

为什么我的代码无法编译?

1个回答

11
item_vec.last()是一个Option<&T>item_vec.last().clone()是另一个Option<&T>。这实际上执行了引用的浅拷贝。这意味着你并没有真正地解决任何问题!
直观上讲,这是有道理的 - 克隆指针可以返回一个值类型,直接存储在堆栈上,但是Option<&T>的克隆不能克隆T,因为它没有地方放置它。
这是因为一个 Option<T> 实际上在一个 &T 上调用了 clone,所以 Option<&T> 在一个 &&T 上调用了 clone,这意味着特质中的 &self 参数解析为 self = &T。这意味着我们使用 &TClone 实现
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()仍然是对向量的借用。

可以采取两种基本方式进行修复。一种方法是使用Optioncloned方法,它可以克隆内部引用:

item_vec.last().cloned().unwrap()

这个实现是在内部数据中作为一个map实现的:

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

另一种选择是先取消包装,然后再克隆引用,以获取值:

unwrap 并仅在此之后 clone 引用即可。

item_vec.last().unwrap().clone()

谢谢您的解释!但我还有一些问题。1.使用cloned()的第一个解决方案运行良好,但第二个解决方案仍然存在相同的错误。为什么会这样?2.整数版本的代码为什么可以在没有所有这些更正的情况下工作? - Remagpie
@Yang 第二个解决方案多了一个 "*",请再试一次看看现在是否可以工作。整数版本可行是因为整数是 Copy 类型,这意味着赋值 let new = *ref 会导致复制而不是移动。我在其他地方更详细地讨论了移动和复制的区别。 - Veedrac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接