【问题标题】:How to clone last element from vector?如何从向量中克隆最后一个元素?
【发布时间】:2015-11-01 16:17:12
【问题描述】:

我正在尝试编写代码来获取某个向量的最后一个元素,并根据该元素执行不同的操作(包括向量的突变)。

我试过这样:

#[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,
    }
}

编译器不会抱怨借用。

为什么我的代码编译失败?

【问题讨论】:

    标签: rust


    【解决方案1】:

    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 .这意味着我们使用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() 因此仍然是向量的借用。

    可以通过两种基本方式解决此问题。一种是使用Option's cloned method,它将内部引用克隆掉:

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

    另一个选项是 unwrap 并且只有 然后 clone 引用,以获取值:

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

    【讨论】:

    • 感谢您的解释!但我还有一些问题。 1. cloned() 的第一个解决方案效果很好,但第二个解决方案仍然有同样的错误。为什么会发生这种情况? 2. 为什么整型版本的代码在没有这些修正的情况下也能工作?
    • @Yang 第二个解决方案不小心多了一个“*”;再试一次,看看它现在是否有效。整数版本有效,因为整数是Copy,这意味着赋值let new = *ref 会导致复制,而不是移动。 I've talked more about moves vs. copies elsewhere.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多