条件特征边界可能吗?

时间:2021-03-17 09:04:10

标签: rust traits

baz 中的 trait bound 在 flag=true 时不必要地强,在这种情况下,我们只需要 Foo

我希望 baz 可以接受 where T: Foo 并且Bar 时强制执行 flag=false 绑定。

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)

........^ 特征 Bar 没有为 T

实现

引入一个可以被 quux 类型调用的新函数 !Bar 可能是我必须接受的解决方案。 但是有没有办法让 Bar!Bar 类型都可以访问单个函数 baz

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

1 个答案:

答案 0 :(得分:3)

我相信您所要求的在当前的 Rust 中是不可能的,因为它需要 specialization。通过 RFC 提出的专业化,baz 可以使用辅助特征实现,其中包含 T: Foo 的全面实现和 T: 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 中的可编译代码。)