2017-08-04 10 views
2

私は、異なる特性オブジェクトへの変換を管理する特性を持っています。形質オブジェクトを別の形質オブジェクトにキャストする形質を自動実装することは可能ですか?

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

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

が、私は今、自動的に構造体がBoo/Gee実装した場合には、これにこの実装を変更したい定型コードの量を減らすために(BooGeeは両方の異なる形質は): 特性は次のようになります

#[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を2回実装することができないため、この方法では動作しません。これは私が知る限り錆には対応していません。

// 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それぞれを動かすことによって、我々は重複実装を避けます。スーパーオブジェクトからのメソッドは特性オブジェクトで使用できるので、Fooas_booas_geeを再宣言する必要はありません。


これはBooGeeが近い常に実装するのある場合には素晴らしい作品が、これが当てはまらないとき、それはまだ手動で実装する必要があります。私のプログラムでは、as_geeがすべての呼び出しの約80%でNoneを返すべきであるという事実を考えると、これはむしろ残念です。

specialization(これはRust 1.19では安定していないので、夜間コンパイラを使用する必要があります)を使用して解決できます。 as_booas_geeの実装を、すべてのタイプに適用されるimpl(特性の定義からFooAsBooFooAsGeeを実装するように)に移す必要があります。

+0

'Boo'と' Gee'が*常に実装されている*の場合にはうまくいくが、そうでない場合は手作業で実装する必要がある。私のプログラムでは、 'as_gee'がすべての呼び出しの約80%で' None'を返すべきであるという事実を考えると、これはむしろ残念です。 – SleepingPanda

関連する問題