我目前不知道如何协调 Rust 中的某种设计模式。该模式涉及具有通用功能的特征,该功能受到某些标记特征的限制。 对于这个问题,假设不可能修改 Foo
或FooMarker
.我已经知道do_foo
应该被放置在一个单独的特征中,而不是使用标记特征,但我不是做出这个决定的人。
trait Foo {
fn do_foo<T>(&mut self, _: &T) where Self: FooMarker<T>;
fn do_bar(&mut self);
}
/// Indicates that a specific type is supported for doing Foo.
trait FooMarker<T>: Foo {}
乍一看这可能看起来很合理,但尝试以通用方式使用此模式感觉几乎是不可能的。例如,采用扩展 Foo
功能的包装器结构的通常微不足道的情况。 。最初我认为这个实现可能会按预期工作,但它遇到了许多问题。
struct FooWrapper<F> {
inner_foo: F
}
impl<F: Foo> Foo for FooWrapper<F> {
fn do_foo<T>(&mut self, x: &T) where Self: FooMarker<T> {
do_extra_stuff();
self.inner_foo.do_foo(x)
}
fn do_bar(&mut self) {
self.inner_foo.do_bar();
}
}
impl<T, F: FooMarker<T>> FooMarker<T> for FooWrapper<F> {}
Rust Playground
从概念上讲,我们也许可以看看这个并知道 FooWrapper<F>: FooMarker<T>
意味着F: FooMarker<T>
,但编译器不想依赖此信息。想了想,这倒是有几分道理。无处 impl Foo for FooWrapper
我们需要F: FooMarker<T>
吗? .
我该如何写FooWrapper
无需重写 Foo
或FooMarker
?
最佳答案
恐怕你不能,除非我遗漏了一些东西。
impl<T, F: FooMarker<T>> FooMarker<T> for FooWrapper<F> {}
告诉我们如果F
实现FooMarker<T>
,然后FooWrapper<F>
也有。但反之则不一定成立,如下所示:
struct Bar;
struct Baz;
impl Foo for FooWrapper<Bar> {
fn do_foo<T>(&mut self, _: &T)
where
Self: FooMarker<T>
{}
}
impl FooMarker<Baz> for FooWrapper<Bar> {}
我们无法更改 where
子句,因为它是在 Foo
的声明中定义的.
对我来说真正的解决方案是制作 Foo
本身是通用的,我理解你正在考虑:
trait Foo<T> {
fn do_foo(&mut self, _: &T);
}
坦率地说,我从未见过这样的“标记”模式(除非可能涉及密封特征的上下文,不确定),而且我不知道它有什么帮助。
关于rust - 当特征函数依赖于为 Self 实现的通用标记特征时,实现通用包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75138283/