2015-07-12 53 views
4

PhantomDataCopy以令人惊讶的方式进行交互:复制特质和PhantomData:这个真的应该移动吗?

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; 

我还以为,对于Val<Meters>获得Copy会给Val<Meters>复制语义。但显然,只有在Val的类型参数T也实现了Copy时,才是如此。我不明白为什么。

PhantomData总是执行Copy,regardless of whether its type parameter does。无论如何,如果PhantomData<Meters>没有实现Copy,我希望编译器抱怨它不能派生CopyVal<Meters>。相反,编译器为Val<Meters>愉快地派生Copy,但它适用移动语义。

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

回答

3

我以为衍生副本为Val<Meters>会给Val<Meters>复制语义。

Copy没有被导出Val<Meters>,只是所有Val<T>其中T本身是Copy

在Github上有几个未解决的问题,例如, this one。我的印象是,这不是有意的,但只是derive目前的作品的限制。

您可以解决此通过手工写一个毯子IMPL为CloneCopy

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

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

我有同样的印象很好,因为据我所知'仿制药使用derive'只尝试实施性状是基于通用参数本身是否已经实现它。我怀疑潜在的问题是,决定实现这个特征是否可行实际上是相当复杂的,因此它现在只是尽力而为;请注意,当'derive'失败时,您可以轻松移动到手动实现。 –

+0

这是令人惊讶的:所有'Val'字段都保证实现'Copy',而不管'T'的类型如何,因为'PhantomData'总是实现'Copy'。同样奇怪的是(但与你的评论一致)是因为编译器不能保证'T'实现'Copy',所以''''''''''''''''''''''''''''''''''''''''''看起来这应该不重要:[docs](http://doc.rust-lang.org/std/marker/trait.Copy.html)表示“一个类型可以实现'Copy',如果它的全部组件实现'Copy'。“文档没有说所有的*类型参数都必须实现'Copy'。 – rlkw1024

+0

@ rlkw1024是的,整个情况并不理想。整个标准库中都有类似[this one](https://github.com/rust-lang/rust/blob/master/src/libcollections/linked_list.rs#L66)的fixms。我不确定这是否是一个实际的问题,但我已经更新了我的答案,以显示如何为您的类型手动实现'Copy'。 – fjh