2016-07-20 16 views
1

我試圖有一個Rust特質X,它要求任何人執行X可以轉換爲其他實現X要求特質實現可以相互轉換

所以我試圖使X聲明強制執行此像這樣:

trait X<T> : From<T> where T: X {} 

但是,編譯器告訴我,它不會在我的T規格找到任何類型的參數,因爲T: X需要一些類型信息T: X<...>。但這樣總會有一種類型的論點太少;例如

trait X<T, U> : From<T> where T: X<U> {} 

我能以某種方式解決這個問題嗎?不允許做where T: X<_>

+1

我不知道這是什麼應該做,但是'X'不是一個特點:它是一個通用的,當你在一個類型取代了'T'參數,*結果*在特徵。換句話說,'T:X'將不起作用;你需要'T:X ',因爲它是有道理的。 –

+0

*任何實現'X'的人都可以轉換爲'X'的其他實現*可能我錯過了一些東西,但是這不應該是不可能的嗎?即使一種類型是在第一種類型之後的幾年內寫入的,您是否要求可能無限類型的一種類型必須可以轉換爲該集合中的任何其他類型? – Shepmaster

+0

@DK嗯,是的,'X'當然需要一個規範,當然這是一個類型參數。但是,如果我更新定義以讀取'特徵X :從其中T:X {}'編譯器仍然告訴我我的類型參數太少。現在只需要兩個,只找到一個,而不是期待一個,找到零。 – KasMA1990

回答

3

而不是試圖限制實施者,我認爲這將是簡單的提供實現爲特徵的一部分:

trait Length { 
    fn unit_in_meters() -> f64; 

    fn value(&self) -> f64; 
    fn new(value: f64) -> Self; 

    fn convert_to<T:Length>(&self) -> T { 
     T::new(self.value() * Self::unit_in_meters()/T::unit_in_meters()) 
    } 
} 

struct Mm { 
    v: f64, 
} 

impl Length for Mm { 
    fn unit_in_meters() -> f64 { 0.001 } 

    fn value(&self) -> f64 { self.v } 
    fn new(value: f64) -> Mm { 
     Mm{ v: value } 
    } 
} 

struct Inch { 
    v: f64, 
} 

impl Length for Inch { 
    fn unit_in_meters() -> f64 { 0.0254 } 

    fn value(&self) -> f64 { self.v } 
    fn new(value: f64) -> Inch { 
     Inch{ v: value } 
    } 
} 

fn main() { 
    let foot = Inch::new(12f64); 
    let foot_in_mm: Mm = foot.convert_to(); 
    println!("One foot in mm: {}", foot_in_mm.value()); 
} 

Play link

爲了好玩,與associated_consts功能,您可以交換恆定轉換因子的方法。

#![feature(associated_consts)] 
trait Length { 
    const UNIT_IN_METERS: f64; 

    fn value(&self) -> f64; 
    fn new(value: f64) -> Self; 

    fn convert_to<T:Length>(&self) -> T { 
     T::new(self.value() * Self::UNIT_IN_METERS/T::UNIT_IN_METERS) 
    } 
} 

struct Mm { 
    v: f64, 
} 

impl Length for Mm { 
    const UNIT_IN_METERS: f64 = 0.001; 

    fn value(&self) -> f64 { self.v } 
    fn new(value: f64) -> Mm { 
     Mm{ v: value } 
    } 
} 

struct Inch { 
    v: f64, 
} 

impl Length for Inch { 
    const UNIT_IN_METERS: f64 = 0.0254; 

    fn value(&self) -> f64 { self.v } 
    fn new(value: f64) -> Inch { 
     Inch{ v: value } 
    } 
} 

fn main() { 
    let foot = Inch::new(12f64); 
    let foot_in_mm: Mm = foot.convert_to(); 
    println!("One foot in mm: {}", foot_in_mm.value()); 
} 

Play link

+0

Oooh,很好!我玩過類似的概念(雖然你的方式更好),但是我放棄了它,因爲我不想支付不必要計算的運行時成本。你知道編譯器在使用相關的常量值時是否計算它們嗎?至少我假定編譯器在第一個概念中不這樣做。 編輯:另外,你知道如果associated_const是一個夜間功能,因爲它是門控嗎? – KasMA1990

+0

是的,associated_const功能目前只在夜間使用。我認爲它比較好,在釋放模式下,在生成的ASM中,我看不到任何對convert_to()或unit_in_meters()的引用。我也看不到任何MUL,因此它可能都是經過不斷評估的,但是在x86彙編上我有點生疏,所以可能錯過了某些東西。 –

+0

好的,謝謝;那麼你的方法肯定會更好,那麼我所做的一切:) – KasMA1990