复制trait和PhantomData:这真的应该移动吗?

时间:2015-07-12 18:16:52

标签: rust

PhantomData以令人惊讶的方式与Copy互动:

use std::marker::PhantomData;

#[derive(Copy, Clone)]
pub struct Seconds;

pub struct Meters;

#[derive(Copy, Clone)]
pub struct Val<T> {
    pub v: PhantomData<T>
}

fn main() {
    let v1: Val<Seconds> = Val {v: PhantomData};
    let v2 = v1;
    let v3 = v1;

    let v4: Val<Meters> = Val {v: PhantomData};
    let v5 = v4;
    let v6 = v4;
}

这失败如下:

src/main.rs:20:13: 20:15 error: use of moved value: `v4` [E0382]
src/main.rs:20         let v6 = v4;
                           ^~
src/main.rs:19:13: 19:15 note: `v4` moved here because it has type `Val<Meters>`, which is moved by default
src/main.rs:19         let v5 = v4;

我认为为Copy派生Val<Meters>会给出Val<Meters>复制语义。但显然,只有在Val类型参数T也实现Copy的情况下,这才是真的。我不明白为什么。

PhantomData始终实施Copyregardless of whether its type parameter does。无论如何,如果PhantomData<Meters>没有实现Copy,我希望编译器抱怨它无法为Copy派生Val<Meters> 。相反,编译器愉快地为Copy派生Val<Meters>,但它应用了移动语义。

这种行为是故意的吗?如果是这样,为什么?

1 个答案:

答案 0 :(得分:4)

  

我认为为Val<Meters>派生复制会给Val<Meters>复制语义。

Copy并非导出Val<Meters>,仅适用于Val<T>本身为T的所有Copy

Github上有几个未解决的问题,例如: this one。我的印象是,这不是故意的,而只是derive目前的工作方式的限制。

您可以通过为CloneCopy手动编写毛毯impl来解决此问题:

impl <T> Clone for Val<T> {
    fn clone(&self) -> Val<T> {
        Val {v: PhantomData}
    }
}

impl <T> Copy for Val<T> {}