我有一个管理到不同特征对象的转换的特征。
该特征如下所示:(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)
}
}
但如果我也想为 Gee
自动实现 Foo
,那么由于我无法实现 Foo
两次,据我所知 Rust 不支持。
// 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
也许可以实现这一点但我找不到任何深入的解释,所以我现在有点陷入困境。
最佳答案
这个问题可以通过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
移动到各自的特征,我们避免了重叠的实现。来自 supertraits 的方法在特征对象中可用,因此 Foo
不必重新声明 as_boo
和 as_gee
。
While this works great in cases where
Boo
andGee
are close to always implemented, it still requires manual implementation when this is not the case. Considering the fact that as_gee should returnNone
in about 80% of all calls in my program this is rather unfortunate.
我们可以使用 specialization 来解决这个问题(从 Rust 1.19 开始还不稳定,所以你需要使用 nightly 编译器)。我们需要将 as_boo
和 as_gee
的实现从特征定义移动到适用于所有类型的 impl
,以便所有类型都实现 FooAsBoo
和FooAsGee
。
#![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
}
}
关于generics - 是否可以自动实现将一个特征对象转换为另一个特征对象的特征?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45501780/