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

rlk*_*024 5 rust

PhantomDataCopy以令人惊讶的方式进行交互:

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;
}
Run Code Online (Sandbox Code Playgroud)

这失败如下:

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;
Run Code Online (Sandbox Code Playgroud)

我会认为获得CopyVal<Meters>会给Val<Meters>拷贝语义.但显然,只有在Val类型参数T也实现的情况下才是真的Copy.我不明白为什么.

PhantomData总是实现Copy,无论其类型参数是否如此.总之和,如果PhantomData<Meters>没有实现Copy,我期望编译器抱怨说,它不能获得CopyVal<Meters>.相反,编译器愉快地得出CopyVal<Meters>,但它适用于移动语义.

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

fjh*_*fjh 5

我认为派生 Copy forVal<Meters>会提供Val<Meters>复制语义。

Copy不是为 派生的Val<Meters>,只是为它本身Val<T>所在的所有地方。TCopy

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

您可以通过手动为Cloneand编写一个全面的实现来解决这个问题Copy

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

impl <T> Copy for Val<T> {}
Run Code Online (Sandbox Code Playgroud)

  • 它与 `PhantomData` 无关,类型为 `&amp;'a T` 的字段也会以同样的方式失败。这是关于派生如何处理类型参数。 (2认同)