我有一个特性来管理对不同特征对象的转换。
特征如下所示:(Boo
和Gee
都是不同的特征)
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)
}
}
但是,如果我还想为Foo
自动实施Gee
,那么由于我无法实现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
来实现这一点,但我找不到任何深入解释它们,所以我现在有点陷入困境。
答案 0 :(得分: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_boo
和as_gee
各自移动到自己的特征,我们避免了重叠的实现。特质对象中提供了超级特征的方法,因此Foo
无需重新声明as_boo
和as_gee
。
虽然这在
Boo
和Gee
关闭始终实施的情况下效果很好,但在不是这种情况时仍需要手动实施。考虑到as_gee应该在我的程序中大约80%的所有调用中返回None
,这是非常不幸的。
我们可以使用specialization解决这个问题(从Rust 1.19起不稳定,所以你需要使用夜间编译器)。我们需要将as_boo
和as_gee
的实现从特征定义移动到适用于所有类型的impl
,以便所有类型实现FooAsBoo
和{{1} }。
FooAsGee