有条件的特征界限可能吗?

Conditional trait bounds possible?

baz 中的 trait bound 对于 flag=true 来说是不必要的强,在这种情况下我们只需要 Foo.

我想让 baz 可以接受 where T: Foo 只有 flag=false 时强制执行 Bar 绑定。

trait Foo {}
trait Bar: Foo {}

fn foo<T>(t: T) where T: Foo {}
fn bar<T>(t: T) where T: Bar {}

fn baz<T>(t: T, flag: bool) 
where T: Bar 
{
    if flag {
        foo(t);
    } else {
        bar(t);
    }
}

将绑定更改为 where T: Foo 当然不会编译:

bar(t)

.........^ the trait Bar is not implemented for T

引入一个可以被!Bar类型调用的新函数quux可能是我不得不接受的解决方案。 但是有什么方法可以让 Bar!Bar 类型都访问一个函数 baz?

如果 flag=falseT: !Bar 可接受,则涉及运行时恐慌的解决方案。

我相信你所要求的在当前的 Rust 中是不可能的,因为它需要 specialization. With specialization as proposed by the RFCbaz 可以使用辅助特性来实现 T: FooT: Bar.

的专门实现

遗憾的是,目前专业化似乎不是优先事项(被 const 泛型等更重要的功能所取代),因此它需要一段时间才能实现和稳定。尽管如此,为了好玩,这里是一个基于当前夜间发现的专业化的实现:

#![feature(specialization)]

trait Foo {}
trait Bar: Foo {}

fn foo<T: Foo>(_t: T) -> &'static str {
    "foo"
}
fn bar<T: Bar>(_t: T) -> &'static str {
    "bar"
}

trait Dispatch {
    fn dispatch(self, flag: bool) -> &'static str;
}

impl<T: Foo> Dispatch for T {
    default fn dispatch(self, flag: bool) -> &'static str {
        // there is no way to call bar(self) here, so we can only assert the flag is true
        assert!(flag);
        foo(self)
    }
}

impl<T: Bar> Dispatch for T {
    fn dispatch(self, flag: bool) -> &'static str {
        if flag {
            foo(self)
        } else {
            bar(self)
        }
    }
}

fn baz<T: Foo>(t: T, flag: bool) -> &'static str {
    t.dispatch(flag)
}

fn main() {
    struct A;
    impl Foo for A {}
    assert_eq!(baz(A, true), "foo");
    //baz(A, false) panics

    struct B;
    impl Foo for B {}
    impl Bar for B {}
    assert_eq!(baz(B, true), "foo");
    assert_eq!(baz(B, false), "bar");
}

(可编译代码在playground.)