2017-08-04 78 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

相关问题