【问题标题】:Can I specialise a trait on a nested type?我可以在嵌套类型上专门化一个特征吗?
【发布时间】:2019-08-11 13:48:35
【问题描述】:

我有一个队列 @9​​87654323@ 特征,其中实现了 MonotonicLastTick 在我要插入的类型上参数化:

struct Monotonic<T> {
    items: Vec<T>,
}
struct LastTick<T> {
    items: Vec<T>,
}

struct SetDelta;

trait Strategy<T> {
    type T;
    fn enqueue(&mut self, v: T);
    fn has_pending(&self) -> bool;
}

impl<T> Strategy<T> for Monotonic<T> {
    type T = Self;
    fn enqueue(&mut self, v: T) {
        self.items.push(v);
    }
    fn has_pending(&self) -> bool {
        !self.items.is_empty()
    }
}

impl<T> Strategy<T> for LastTick<T> {
    type T = Self;
    fn enqueue(&mut self, v: T) {
        self.items.push(v);
    }
    fn has_pending(&self) -> bool {
        !self.items.is_empty()
    }
}

impl<T> Strategy<T> for LastTick<T> {
    type T = Self;
    fn enqueue(&mut self, v: T) {
        self.items.push(v);
    }
    fn has_pending(&self) -> bool {
        !self.items.is_empty()
    }
}

impl<T> LastTick<T> {
    fn new() -> Self {
        LastTick { items: Vec::new() }
    }
}
impl<T> Monotonic<T> {
    fn new() -> Self {
        Monotonic { items: Vec::new() }
    }
}

#[test]
fn monotonic_scalar_queue() {
    let mut a = Monotonic::<f64>::new();
    a.enqueue(123.4);
    assert!(a.has_pending());
}

#[test]
fn monotonic_list_queue() {
    let mut a = Monotonic::<[f64; 3]>::new();
    a.enqueue([123.4, 345.8, 324.1]);
    assert!(a.has_pending());
}

#[test]
fn monotonic_tuple_queue() {
    let mut a = Monotonic::<(f64, String, u32)>::new();
    a.enqueue((123.4, "hello".into(), 324));
    assert!(a.has_pending());
}

以上工作正常。我想为行为略有不同的HashSet 保留相同的界面。

#[test]
fn monotonic_set_queue() {
    let mut a = Monotonic::<HashSet<f64>>::new();
    // I want to insert a f64 and implement the logic of the hashset in
    // the implementation, but it expects a new HashSet
    a.enqueue(123.4);
    assert!(a.has_pending());
}

我试过了

impl<T> Strategy<T> for Monotonic<HashSet<f64>> {
    type T = Self;
    fn enqueue(&mut self, v: T) {
        self.items.push(v);
    }
    fn has_pending(&self) -> bool {
        !self.items.is_empty()
    }
}

还有

impl Strategy<f64> for Monotonic<f64> {
    type T = HashSet<f64>;
    fn enqueue(&mut self, v: f64) {
        self.items.push(v);
    }
    fn has_pending(&self) -> bool {
        !self.items.is_empty()
    }
}

结果不同,但没有运气。有没有办法轻松指定?

【问题讨论】:

标签: rust


【解决方案1】:

您似乎想要Monotonic&lt;T&gt; 的不同实现,其中集合不是Vec - 这对于您当前定义Monotonic 的方式是不可能的。相反,您可以创建另一个类型 MonotonicHashSet&lt;T&gt;,并使用 HashSet 作为支持集合。

相反,如果您想让Monotonic 接受不同的集合类型,那么您可能还希望在集合类型上对其进行泛化。然而,这可能会很快变得复杂。在 Rust 中,我们通常与集合相关联的属性被拆分为多个特征,在 iter module 中定义。它们被拆分,以便每个集合类型都可以针对集合所具有的任何约束,精确且正确地定义其行为。因此,对于您的 MonotonicLastTick 类型,重要的是要考虑您可能有哪些要求,以及您需要哪些特征才能将集合与该类型一起使用。

最后一点:虽然Vec 接受任何类型的T,但HashSet 需要与Eq 特征完全相等,并且通过Hash 特征具有哈希性。这些不同的要求值得考虑,因为与例如 C# 不同,Rust 没有为所有类型提供这些操作的默认实现 - 您必须提供它们或 #[derive()] them

【讨论】:

  • 最后一件事 - 浮点类型 (f32& f64) 不实现 EqHash - Eq,因为 NaN 不等于任何数字或本身;和Hash,因为对于如何处理 +/-0、NaN、非正规数没有达成共识,并且表示相同数字的不同位表示(可能散列不同)存在问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
  • 2013-01-08
  • 2015-09-21
相关资源
最近更新 更多