Могу ли я специализировать черту на вложенном типе? - PullRequest
0 голосов
/ 20 марта 2019

У меня есть черта очереди Strategy с реализациями для Monotonic и LastTick, параметризованными для типа, который я хочу вставить:

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 Ответ

1 голос
/ 20 марта 2019

Похоже, вам нужна другая реализация Monotonic<T>, где коллекция не является Vec - это невозможно при том способе, который вы в настоящее время определили Monotonic.Вместо этого вы можете создать другой тип MonotonicHashSet<T> и использовать HashSet в качестве резервной коллекции.

Если вместо этого вы хотите, чтобы Monotonic принимала другие типы коллекций, вы можете захотетьтакже обобщите это по типу коллекции.Это, однако, может быстро усложниться.В Rust свойства, которые мы обычно связываем с коллекциями, разбиты на несколько признаков, определенных в модуле iter .Они разделены, так что каждый тип коллекции может детально и корректно определять свое поведение для любых ограничений, которые имеет коллекция.Итак, для ваших типов Monotonic и LastTick важно учитывать, какие требования у вас могут возникнуть, и какие черты означают, что вам потребуется для использования коллекций с этим типом.

Последнее замечание:В то время как Vec принимает любой тип T, для HashSet требуется полное равенство от черты Eq и хеш-способности - от черты Hash.Эти различные требования заслуживают внимания, потому что в отличие от, например, C #, Rust не предоставляет реализации этих операций по умолчанию для всех типов - вы должны предоставить их или #[derive()] их .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...