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=false
和 T: !Bar
可接受,则涉及运行时恐慌的解决方案。
答案 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 中的可编译代码。)