2017-08-04 86 views
2

我有一個管理轉換爲不同特質對象的特質。 的特點如下:(BooGee都是不同的性狀)是否可以自動實現將特質對象轉換爲另一個特徵對象的特徵?

trait Foo { 
    fn as_boo(&mut self) -> Option<&mut Boo> { 
     None 
    } 

    fn as_gee(&mut self) -> Option<&mut Gee> { 
     None 
    } 
} 

爲了減少我現在要自動更改此實現這情況下,結構實現Boo/Gee的樣板代碼量:

#[derive(Boo)] 
struct W {} 

impl Foo for W { 
    fn as_boo(&mut self) -> Option<&mut Boo> { 
     Some(self) 
    } 
} 

我能做到這一點,如果只有一個其他特質我有使用泛型轉換爲:

impl<T: Boo> Foo for T { 
    fn as_boo(&mut self) -> Option<&mut Boo> { 
     Some(self) 
    } 
} 

但是,如果我也想自動執行FooGee它不會這樣工作,因爲我無法實現Foo兩次,這是不支持生鏽,據我所知。

// This does not compile because Foo might get implemented twice. 
impl<T: Boo> Foo for T { 
    fn as_boo(&mut self) -> Option<&mut Boo> { 
     Some(self) 
    } 
} 

impl<T: Gee> Foo for T { 
    fn as_gee(&mut self) -> Option<&mut Gee> { 
     Some(self) 
    } 
} 

可能可以實現這一目標使用Procedural Macros,但我找不到任何在他們深入的解釋,所以我有種現在卡住。

+1

據我所知,程序宏不能訪問類型信息,所以你將無法決定類型是否需要重寫默認方法。 – red75prime

回答

2

這個問題可以通過introducing an extra level of indirection解決:

trait Boo {} 
trait Gee {} 

trait FooAsBoo { 
    fn as_boo(&mut self) -> Option<&mut Boo> { 
     None 
    } 
} 

trait FooAsGee { 
    fn as_gee(&mut self) -> Option<&mut Gee> { 
     None 
    } 
} 

trait Foo: FooAsBoo + FooAsGee {} 

impl<T: Boo> FooAsBoo for T { 
    fn as_boo(&mut self) -> Option<&mut Boo> { 
     Some(self) 
    } 
} 

impl<T: Gee> FooAsGee for T { 
    fn as_gee(&mut self) -> Option<&mut Gee> { 
     Some(self) 
    } 
} 

impl<T: FooAsBoo + FooAsGee> Foo for T {} // if there's nothing else in Foo 

struct W; 
impl Boo for W {} 
impl Gee for W {} 

fn main() { 
    let mut w = W; 
    let foo = &mut w as &mut Foo; 
    let boo = foo.as_boo(); 
} 

通過移動as_booas_gee每個自己的特點,我們避免了重疊的實現。超特徵的方法可用於特徵對象,因此Foo不必重新聲明as_booas_gee


雖然其中BooGee接近始終實施這一工程在大的情況下,它仍然需要手工執行時,這是情況並非如此。考慮到as_gee應該返回None在我的程序中所有電話的約80%,這是相當不幸的事實。

我們可以通過使用specialization(它不像Rust 1.19那樣穩定,所以你需要使用夜間編譯器)來解決這個問題。我們需要將as_booas_gee的實現從特徵定義移至適用於所有類型的impl,以便所有類型實現FooAsBooFooAsGee

#![feature(specialization)] 

trait FooAsBoo { 
    fn as_boo(&mut self) -> Option<&mut Boo>; 
} 

trait FooAsGee { 
    fn as_gee(&mut self) -> Option<&mut Gee>; 
} 

impl<T> FooAsBoo for T { 
    default fn as_boo(&mut self) -> Option<&mut Boo> { 
     None 
    } 
} 

impl<T> FooAsGee for T { 
    default fn as_gee(&mut self) -> Option<&mut Gee> { 
     None 
    } 
} 
+0

儘管在Boo和Gee總是被實現的情況下,這種方法非常有效,但如果不是這種情況,仍然需要手動執行。考慮到我的程序中大約80%的調用中'as_gee'應該返回'None',這是一個相當不幸的事實。 – SleepingPanda

相關問題