如何从for循环中检索用户定义的类型?

时间:2014-11-15 03:57:25

标签: reference rust borrow-checker

我定义了一个Attribute类型,我有一个Vec<Attribute>我正在循环检索&#34; best&#34;一。这与我的第一次尝试类似:

#[derive(Debug)]
struct Attribute;

impl Attribute {
    fn new() -> Self {
        Self
    }
}

fn example(attrs: Vec<Attribute>, root: &mut Attribute) {
    let mut best_attr = &Attribute::new();
    for a in attrs.iter() {
        if is_best(a) {
            best_attr = a;
        }
    }
    *root = *best_attr;
}

// simplified for example
fn is_best(_: &Attribute) -> bool {
    true
}

我遇到了以下编译错误:

error[E0507]: cannot move out of borrowed content
  --> src/lib.rs:17:13
   |
17 |     *root = *best_attr;
   |             ^^^^^^^^^^ cannot move out of borrowed content

在搜索了一些解决方案后,我通过执行以下操作解决了错误:

  1. #[derive(Clone)]结构
  2. 添加Attribute属性
  3. *root = best_attr.clone();
  4. 替换最终陈述

    我不完全理解为什么会这样,我觉得这对我遇到的问题是一个粗略的解决方案。这是如何解决这个错误的,这是解决这个问题的正确方法吗?

1 个答案:

答案 0 :(得分:2)

您正在体验Rust内存模型的基础:

  • 每个对象都可以(并且必须!)仅由一个其他对象拥有
  • 大多数类型从不隐式复制,始终移动(有一些例外:实现Copy的类型)

以此代码为例:

let x = String::new();
let y = x;
println!("{}", x);

它会生成错误:

error[E0382]: borrow of moved value: `x`
 --> src/main.rs:4:20
  |
3 |     let y = x;
  |             - value moved here
4 |     println!("{}", x);
  |                    ^ value borrowed here after move
  |
  = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
类型x

String不可隐式复制,因此已移动yx不能再使用了。

在您的代码中,当您撰写*root = *best_attr时,您首先取消引用引用best_attr,然后将解除引用的值分配给*root。您的Attribute类型不是Copy,因此此分配应为移动

然后,编译器抱怨:

cannot move out of borrowed content

实际上,best_attr是一个不可变引用,允许你拥有它背后的值(它甚至不允许修改它)。允许这样的移动会使对象拥有引用后面的值处于未定义状态,这正是Rust旨在防止的。


在这种情况下,您最好的选择是创建一个与第一个具有相同值的新对象,这正是特征Clone的作用。

#[derive(Clone)]允许您将结构标记为Clone - 只要其所有字段均为Clone。在更复杂的情况下,您必须手动实施这一特性。