函数来接受由几个特征中的任意一个约束的参数



我有一个函数(我们称之为foo<T>(x: &mut T)),它需要对其参数调用特定的方法(我们称其为x.bar())。问题是,存在两个不同的特征,它们定义了具有完全相同语义的方法bar(我们称它们为A::BarB::Bar)。所以我希望函数接受A::BarB::Bar

如果它们是structs,我可以简单地为它们定义一个新的特性。如果只有一个是trait,我就可以用一揽子定义(impl<T> My::Bar for T where T: A::Bar)和任何剩余结构的显式实现来定义一个新的trait。但它们是两个特征和两个毯覆impls是不允许的。有其他办法解决这个问题吗?也许是通过不同类型的match

很明显,它们不是我的特点。是库中的一个错误定义了它们。我会报告它。但在它被修复之前,我仍然想要一个变通方法。

您可以通过在&T周围编写一个包装器来实现这一点,该包装器显式控制要调用的bar。我不知道有什么更简单的方法可以做到这一点。下面的代码应该是有效的,因为它使用静态调度。

trait A {
    fn bar(&self);
}
trait B {
    fn bar(&self);
}
// This will be our "common ground" trait.
trait Bar {
    #[inline(always)]
    fn bar(&self);
}
// The Bar wrapper for A.
struct ABar<'a, T: 'a + A>(&'a T); //'
impl<'a, T: 'a + A> Bar for ABar<'a, T> { //'
    #[inline(always)]
    fn bar(&self) { self.0.bar(); }
}
// The Bar wrapper for A.
struct BBar<'a, T: 'a + B>(&'a T); //'
impl<'a, T: 'a + B> Bar for BBar<'a, T> { //'
    #[inline(always)]
    fn bar(&self) { self.0.bar(); }
}
// Example type that implements both A and B.
struct Thingy;
impl A for Thingy {
    fn bar(&self) { println!("A::bar()"); }
}
impl B for Thingy {
    fn bar(&self) { println!("B::bar()"); }
}
// Note: I've removed the reference here since the implementations of Bar
// are just wrappers around a reference.
fn foo<T: Bar>(x: T) {
    x.bar();
}
fn main() {
    let thingy = Thingy;
    // Note that we have to be *explicit* about the wrapper.
    foo(ABar(&thingy));
    foo(BBar(&thingy));
}

我认为现在不能用静态调度来实现。你可能可以使用特质对象(取决于你的特质的对象安全性)。

即,如果您定义了枚举:

enum Bars<'a> {
    Bbar(&'a b::Bar),
    Cbar(&'a c::Bar),
}

你可以把你的函数写成这样:

fn foo(bars: &Bars) -> u32 {
    use Bars::*;
    match bars {
        &Bbar(b) => b.foo(),
        &Cbar(c) => c.foo(),
    }
}

playpen示例

最新更新