2017-02-08 29 views
6

我有一個特性,我想提供一種方法。這個方法是用一些幫助者來實現的,這些幫助者沒有任何業務在這個特徵之內,並且不夠平凡,以至於動態多態性比使它們通用更有意義。所以,我必須沿着提供的方法鑄造和自我特質對象

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) { 
     use_trait(self); 
    } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 
} 

fn main() { 
    Struct().provided(); 
} 

,然而,does not compile的行代碼,出現錯誤:

error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied 
--> <anon>:9:19 
    | 
9 |   use_trait(self); 
    |     ^^^^ the trait `std::marker::Sized` is not implemented for `Self` 
    | 
    = help: consider adding a `where Self: std::marker::Sized` bound 
    = note: required for the cast to the object type `Trait` 

我明白爲什麼,但不能保證別人不會執行特徵爲無膠式(從&T where T: Trait轉換爲&Trait需要T: Sized,但聲明不需要)。

但是,建議不會做我需要的。我可以添加

fn needed(&self) -> &str where Self: Sized 

但隨後needed()方法不會&Trait(因爲Trait : ?Sized),這使得事情無用訪問,因爲類型(實際的一個做一些有用的東西)是總是處理爲Arc<Trait>。並加入

trait Trait: Sized 

更差,因爲不允許在所有&TraitTrait作爲一個類型爲未分級的,所以Trait類型不落實特質Trait)。

當然,我可以簡單地

fn use_trait<T: Trait>(x: &T) 

,但有很多背後的實際代碼,所以我不想monomorphisation有尤其是自性狀;否則,始終爲特質對象處理。

有沒有什麼辦法可以告訴Rust所有impl Trait都必須調整大小的類型,這裏有一個方法的定義應該適用於所有類型?

+0

另請參見[Rust Trait對象轉換](http://stackoverflow.com/q/41604107/155423) – Shepmaster

回答

0

增強的@JoshuaEntrekin's answer版本:

助手as_trait功能可以放在一個輔助特徵是獲得毯實施所有類型的Sized試圖實現Trait。然後Trait的實施者不必做任何特別的事情,並且轉換工作。

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait : AsTrait { 
    fn needed(&self) -> &str; 

    fn provided(&self) where Self : AsTrait { 
     use_trait(self.as_trait()); 
    } 
} 

trait AsTrait { 
    fn as_trait(&self) -> &Trait; 
} 

impl<T : Trait + Sized> AsTrait for T { 
    fn as_trait(&self) -> &Trait { self } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 
} 

fn main() { 
    Struct().provided(); 
} 

(在play上)。

也可以簡單地把provided放在輔助性狀中,但是它必須不必要地動態調度到Self的其他方法。


更新:其實一點是,它仍然應該能夠覆蓋provided

現在可以通過使其通用化來進一步改進上述內容。有std::makrer::Unsize,在撰寫本文時這是不穩定的。我們不能讓

trait Trait : Unsize<Trait> 

因爲鏽不允許CRTP,幸好它足以把約束的方法。所以

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) where Self: AsObj<Trait> { 
     use_trait(self.as_obj()); 
    } 
} 

trait AsObj<Tr: ?Sized> { 
    fn as_obj(&self) -> &Trait; 
} 

// For &'a Type for Sized Type 
impl<Type: Trait> AsObj<Trait> for Type { 
    fn as_obj(&self) -> &Trait { self } 
} 

// For trait objects 
impl AsObj<Trait> for Trait { 
    fn as_obj(&self) -> &Trait { self } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 

    fn provided(&self) { 
     println!("Aber dieses Objekt sagt Grüß Gott, Welt!"); // pardon my German, it is rusty. 
    } 
} 

fn main() { 
    let s: &Trait = &Struct(); 
    s.provided(); 
} 

(上play

這最終使其透明的其它版本的實現者。請參閱this users thread

2

您需要Trait及其實現的附加功能as_trait

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) { 
     use_trait(self.as_trait()); 
    } 

    fn as_trait(&self) -> &Trait; 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 

    fn as_trait(&self) -> &Trait { 
     self as &Trait 
    } 
} 

,您可以嘗試在操場上。 (trait objects

+0

「未分類的類型」特徵對象具有大小;兩個'usizes'。沒有物體的裸露特質本身就是一種不確定的類型。 –

+0

你能解釋爲什麼需要'as_trait()'方法,'use_trait(self as&Trait)'不能直接在'provided()'中工作嗎? –

+0

@ChrisEmerson,我會將解釋添加到問題本身。這很明顯,爲什麼它不能以簡單的方式工作。 –