gpt4 book ai didi

具有 "simple"和 "advanced"版本的 Rust 特征

转载 作者:行者123 更新时间:2023-11-29 07:58:07 25 4
gpt4 key购买 nike

我有两个基本相同的特征,但一个提供的接口(interface)比另一个低。给定更高级别的特征,可以轻松实现较低级别的特征。我想编写一个接受任一特征实现的库。

我的具体案例是遍历树的特征:

// "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 提供了一个接口(interface),您可以在其中定义 .children() 函数来列出 child ,以及 .cull()函数来潜在地剔除一个状态。

RawState trait 提供了一个接口(interface),您可以在其中定义函数 .children_with_cull()相反,它遍历子项并在单个函数调用中剔除它们。这允许实现 RawState甚至永远不会产生它知道会被淘汰的 child 。

我想让大多数用户只实现 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;
}

但是编译器会提示模棱两可的重复定义。例如在 DummyState State 的实现, 它会提示 Self::Cost是模棱两可的,因为它无法判断您是否指的是 <Self as State>::Cost , 或 <Self as RawState>::Cost .

最佳答案

考虑到 RawStateState不是 object-safe (因为它们在返回类型中使用 Self),我假设您不打算为这些特征创建特征对象(即没有 &RawState )。

超特质界 State: RawState在处理 trait 对象时最重要,因为 trait 对象只能指定一个 trait(加上从标准库中选择的几个没有方法的白名单 trait,如 CopySendSync )。 trait 对象引用的 vtable 仅包含指向该 trait 中定义的方法的指针。但是如果特征有超特征边界,那么来自这些特征的方法也包含在 vtable 中。因此,一个 &State (如果它是合法的)会让你访问 children_with_cull .

超特征绑定(bind)很重要的另一种情况是当子特征为某些方法提供默认实现时。默认实现可以利用绑定(bind)到从另一个特征访问方法的超特征。

由于您不能使用特征对象,并且您没有 State 中方法的默认实现, 我认为你不应该简单地声明超特性绑定(bind) State: RawState ,因为它没有添加任何内容(事实上,会导致问题)。

使用这种方法,有必要从 RawState 复制成员我们需要实现 State ,正如你所建议的。 State因此将被定义为:

pub trait State: Sized {
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;
}

(请注意,绑定(bind) State: Sized 是必需的,因为我们在 Self 中使用了 ChildrenIteratorRawState 也需要绑定(bind) RawState: Sized。)

最后,我们可以提供一条毛毯implRawState对于所有实现 State 的类型.有了这个impl , 任何实现 State 的类型会自动执行RawState .

impl<T> RawState for T
where
T: State
{
type Cost = <Self as State>::Cost;
type CulledChildrenIterator = std::iter::Empty<(Self, Self::Cost)>; // placeholder

fn cull(&self) -> Option<Self::Cost> { <Self as State>::cull(self) }
fn children_with_cull(&self) -> Self::CulledChildrenIterator {
unimplemented!()
}
}

注意消除名称冲突的语法:<Self as State> .它用于我们复制的两个成员,因此 RawState遵从 State .

关于具有 "simple"和 "advanced"版本的 Rust 特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43714388/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com