有条件的特征界限可能吗?
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=false
和 T: !Bar
可接受,则涉及运行时恐慌的解决方案。
我相信你所要求的在当前的 Rust 中是不可能的,因为它需要 specialization. With specialization as proposed by the 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.)
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 forT
引入一个可以被!Bar
类型调用的新函数quux
可能是我不得不接受的解决方案。
但是有什么方法可以让 Bar
和 !Bar
类型都访问一个函数 baz
?
如果 flag=false
和 T: !Bar
可接受,则涉及运行时恐慌的解决方案。
我相信你所要求的在当前的 Rust 中是不可能的,因为它需要 specialization. With specialization as proposed by the 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.)