【问题标题】:Copy trait and PhantomData: Should this really move?复制特征和 PhantomData:这真的应该移动吗?
【发布时间】:2015-07-14 01:41:39
【问题描述】:

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;
}

失败如下:

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&lt;Meters&gt; 会给出Val&lt;Meters&gt; 复制语义。但显然,只有在Val 的类型参数T 也实现Copy 的情况下,这才是正确的。我不明白为什么。

PhantomData 始终实现Copyregardless of whether its type parameter does。无论如何,如果PhantomData&lt;Meters&gt; 没有实现Copy,我希望编译器会抱怨它无法为Val&lt;Meters&gt; 派生Copy。相反,编译器很乐意为Val&lt;Meters&gt; 派生Copy,但它应用了移动语义。

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

【问题讨论】:

    标签: rust


    【解决方案1】:

    我认为为 Val&lt;Meters&gt; 派生 Copy 会赋予 Val&lt;Meters&gt; 复制语义。

    Copy 不是为Val&lt;Meters&gt; 派生的,而是为所有Val&lt;T&gt; 派生的,其中T 本身就是Copy

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

    您可以通过手动为CloneCopy 编写一揽子实现来解决此问题:

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

    【讨论】:

    • 我也有同样的印象,据我所知,泛型使用的derive 仅尝试根据泛型参数本身是否已经实现它来实现特征。我怀疑潜在的问题是决定是否可以实现该特征实际上非常复杂,因此它目前只是尽最大努力;请注意,当derive 失败时,您可以轻松地转到手动实现。
    • 这令人惊讶:Val 的所有字段都保证实现Copy,无论T 的类型如何,因为PhantomData 始终实现Copy。同样奇怪(但与您的评论一致)是impl&lt;T&gt; Copy for Val&lt;T&gt; 失败,因为编译器不能保证T 实现Copy。这似乎无关紧要:docs 说“如果一个类型的所有组件都实现了Copy,那么它可以实现Copy。”文档并没有说所有 类型参数 也必须实现 Copy.
    • @rlkw1024 是的,整个情况并不理想。整个标准库中都有像this one 这样的修复程序。我不确定这对您来说是否是一个实际的实际问题,但我已经更新了我的答案,以展示如何为您的类型手动实现 Copy
    • 它与PhantomData 无关,&amp;'a T 类型的字段会以同样的方式失败。这是关于派生如何处理类型参数的。
    猜你喜欢
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 2021-03-25
    • 2011-05-16
    相关资源
    最近更新 更多