我可以对嵌套类型进行特化吗?

时间:2019-03-20 18:41:21

标签: rust

我有一个队列Strategy特性,其中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()
    }
}

结果不同,但没有运气。有没有一种方法可以轻松地指定它?

1 个答案:

答案 0 :(得分:1)

似乎您想使用Monotonic<T>的不同实现,其中集合不是Vec,而您当前定义的Monotonic的方式是不可能的。相反,您可以创建另一种类型MonotonicHashSet<T>,并使用HashSet作为后备集合。

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

最后一个注意事项:尽管Vec接受任何类型的T,但是HashSet要求从Eq特性到Hash的完全相等性和哈希性特征。这些不同的要求值得考虑,因为与例如C#不同,Rust并未为所有类型提供这些操作的默认实现-您必须提供它们或#[derive()] them