【发布时间】:2017-09-28 14:09:47
【问题描述】:
我有两个基本相同的特征,但一个提供的接口比另一个低。给定较高级别的特征,可以轻松实现较低级别的特征。我想编写一个接受任一特征实现的库。
我的具体情况是遍历树的特征:
// "Lower level" version of the trait
pub trait RawState {
type Cost: std::cmp::Ord + std::ops::Add<Output = Self::Cost> + std::marker::Copy;
type CulledChildrenIterator: Iterator<Item = (Self, Self::Cost)>;
fn cull(&self) -> Option<Self::Cost>;
fn children_with_cull(&self) -> Self::CulledChildrenIterator;
}
// "Higher level" version of the trait
pub trait State: RawState {
type ChildrenIterator: Iterator<Item = (Self, Self::Cost)>;
fn children(&self) -> Self::ChildrenIterator;
}
// Example of how RawState could be implemented using State
fn state_children_with_cull<S: State> (s: S)
-> impl Iterator<Item = (S, S::Cost)>
{
s.children()
.filter_map(move |(state, transition_cost)|
state.cull().map(move |emission_cost|
(state, transition_cost + emission_cost)
)
)
}
在这里,State trait 提供了一个接口,您可以在其中定义 .children() 函数来列出子项,并定义 .cull() 函数来潜在地剔除一个状态。
RawState trait 提供了一个接口,您可以在其中定义一个函数 .children_with_cull(),它遍历子元素并在单个函数调用中剔除它们。这允许RawState 的实现甚至永远不会生成它知道会被剔除的子代。
我想让大多数用户只实现 State 特征,并根据他们的状态实现自动生成 RawState 实现。但是,在实现State 时,某些部分特征仍然是RawState 的一部分,例如
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct DummyState {}
impl State for DummyState {
type Cost = u32;
type ChildrenIterator = DummyIt;
fn emission(&self) -> Option<Self::Cost> {
Some(0u32)
}
fn children(&self) -> DummyIt {
return DummyIt {};
}
}
会报错,因为类型“Cost”是在 RawState 中定义的,而不是在 State 中。关于潜在的解决方法,在 State 中重新定义 RawState 的所有相关部分,即将 State 定义为
pub trait State: RawState {
type Cost: std::cmp::Ord + std::ops::Add<Output = Self::Cost> + std::marker::Copy;
type ChildrenIterator: Iterator<Item = (Self, Self::Cost)>;
fn cull(&self) -> Option<Self::Cost>;
fn children(&self) -> Self::ChildrenIterator;
}
但是编译器会抱怨模棱两可的重复定义。例如,在State 的DummyState 实现中,它会抱怨Self::Cost 不明确,因为它无法判断您指的是<Self as State>::Cost,还是<Self as RawState>::Cost。
【问题讨论】:
-
你确定你需要两个特征,而不仅仅是一个具有default implementation 和
children_with_cull的特征吗? -
@trentcl:那些宁愿直接实现
RawState的类型仍然必须实现children,即使children没有被直接使用。
标签: rust traits api-design