【问题标题】:Why do I get "cannot move out of `item` because it is borrowed" for a custom type but not a Box?为什么对于自定义类型而不是 Box,我得到“无法移出 `item`,因为它是借来的”?
【发布时间】:2017-07-29 18:29:44
【问题描述】:

代码:

use std::collections::HashSet;
use std::{mem, ptr, fmt};
use std::ops::Deref;

enum Unsafety {
    Normal
}
enum ImplPolarity { Positive }
struct TraitRef;
struct Ty;
struct ImplItem;

enum ItemKind {
    Impl(Unsafety,
             ImplPolarity,
             Option<TraitRef>, // (optional) trait this impl implements
         Box<Ty>, // self
    ),
}

struct Item {
    node: ItemKind,
}

pub struct P<T: ?Sized> {
    ptr: Box<T>
}

impl<T: 'static> P<T> {
    pub fn unwrap(self) -> T {
        *self.ptr
    }
}

impl<T: ?Sized> Deref for P<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.ptr
    }
}

fn main() {

    let mut items = Vec::<P<Item>>::new();

    let mut item2: Item;

    for item in items.drain(..) {

        if let ItemKind::Impl(Unsafety::Normal,
                                   ImplPolarity::Positive,
                                   Some(ref trait_type),
                                   ref for_type) = item.node {
        } else {
//            item2 = *item; // AAA
            item2 = item.unwrap(); // BBB
        }
    }
}

产生编译时错误:

error[E0505]: cannot move out of `item` because it is borrowed
  --> /home/xxx/.emacs.d/rust-playground/at-2017-07-29-204629/snippet.rs:64:21
   |
61 |                                    ref for_type) = item.node {
   |                                                    ---- borrow of `item` occurs here
...
64 |             item2 = item.unwrap();

我不明白两件事:

  1. 为什么它抱怨if 分支中的借用,而我们在else 分支中?它们应该是相互排斥的,借用一个不应影响另一个。

  2. 如果我将let mut items = Vec::&lt;P&lt;Item&gt;&gt;::new(); 中的Vec 替换为Vec&lt;Box&lt;Item&gt;&gt; 并取消注释行AAA 和注释行BBB,那么它会编译。 BoxP 都实现了Deref,所以item.node 表达式应该是一样的。

【问题讨论】:

标签: rust


【解决方案1】:

这是一个更清晰的例子:

struct Item;

struct P<T> {
    ptr: Box<T>,
}

impl<T> P<T> {
    fn new(v: T) -> Self {
        P { ptr: Box::new(v) }
    }
}

impl<T> std::ops::Deref for P<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.ptr
    }
}

fn main() {
    let mut item = P::new(Item);
    // let mut item = Box::new(Item);

    *item;
}

BoxP 都实现了Deref,因此item.node 表达式应该相同。

硬道理时间:搬出Boxspecial-cased in the compiler。它使用Deref。移出Box 会释放内存并为您提供所有权。自己无法实现这种特殊能力。

也许在未来的某个时候会添加一个假设的特征,比如DerefMove。这种特性很难纠正。有一个number of attempts for an RFC for it,但目前没有一个打开。

另见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2018-04-18
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多