2015-07-12 25 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