要理解
yew
解决方案,最好要求编译器转储宏扩展的 AST。这样您就可以准确地看到生成的结构和特征是什么。
我不知道这是否正是在
yew
中的工作原理,但类似的东西是有效的,也许一些丑陋的部分可以隐藏在宏中:
use std::marker::PhantomData;
trait HasProperty<P, How> {}
struct Property1;
struct Property2;
struct WithProperty<P, Tail>(PhantomData<P>, Tail);
fn with<P, Tail>(t: Tail) -> WithProperty<P, Tail> {
WithProperty(PhantomData, t)
}
fn check<P, How>(token: &impl HasProperty<P, How>) {}
struct Directly;
impl<P, Tail> HasProperty<P, Directly> for WithProperty<P, Tail> {}
struct Step<N>(N);
impl<P, P2, Tail, N> HasProperty<P, Step<N>> for WithProperty<P2, Tail> where Tail: HasProperty<P, N> {}
fn main() {
let token1 = with::<Property1, _>(with::<Property2, _>(()));
let token2 = with::<Property1, _>(());
check::<Property1, _>(&token1); // compiles
check::<Property2, _>(&token1); // compiles
check::<Property1, _>(&token2); // compiles
// check::<Property2, _>(&token2); // fails with "the trait bound `(): HasProperty<Property2, _>` is not satisfied"
}
这两个
HasProperty
实现并不重叠,因为它们是针对两个不同的 struct
实现的。 Step
是一个(类似链表的)包装器,指示该属性存在,并且发现 N
会进入 WithProperty
嵌套。
如果你写的是:
with::<Property1, _>(with::<Property2, _>(with::<Property1, _>(())))
然后
check
调用会抱怨多个可能的 impl
。我不知道yew
是否能更优雅地处理这个问题。