Как мне написать функцию для работы с общей картой и ее типом записи? - PullRequest
0 голосов
/ 08 июня 2018

Мне нужна функция, которая защищает мои HashMap от перезаписи уже существующих значений, поэтому я написал простую функцию, подобную этой:

fn insert_or_panic<K, V>(m: &mut HashMap<K, V>, k: K, v: V)
where
    K: Hash + Eq,
{
    use std::collections::hash_map::Entry;
    match m.entry(k) {
        Entry::Vacant(o) => o.insert(v),
        Entry::Occupied(_) => panic!("attempt to overwrite entry in dictionary"),
    };
}

Теперь я хочу обобщить ее для работы с любым видомmap:

fn generic_insert_or_panic<M, K, V>(m: &mut M, k: K, v: V)
where
    K: Hash + Eq,
    M: Map<K, V>,
{
    use std::collections::hash_map::Entry;
    match m.entry(k) {
        Entry::Vacant(o) => o.insert(v),
        Entry::Occupied(_) => panic!("attempt to overwrite entry in dictionary"),
    };
}

Все интересующие меня методы HashMap находятся в его блоке impl, не связанном с какой-либо чертой, поэтому похоже, что мне нужно реализовать новую черту:

trait Map<K: Hash + Eq, V> {
    fn entry(&mut self, key: K) -> Entry<K, V>;
}

Каждая карта имеет свой собственный тип Entry: std::collections::hash_map::Entry или std::collections::btree_map::Entry, и я не вижу подходящей черты для замены Entry.Настало ли время для другой черты?

Я чувствую, что иду не в ту сторону.Как решить эту проблему?


Я только начал изучать Rust, и некоторые из моих проблем могут выглядеть нереально и надуманными, но я ищу способы решения проблем, а не обходить ихили, по крайней мере, знать ограничения языка.


FAQ объясняет , что типы с более высоким родом могут решить эту проблему, но это большая особенность, так что ржавчина хочетподходите к нему осторожно.

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Настало ли время для другой черты?

Да.Никому не нужно иметь это конкретное универсальное выражение, поэтому вы можете абстрагироваться от них самим.

trait InsertOrPanic<K, V> {
    fn generic_insert_or_panic(&mut self, k: K, v: V);
}

use std::collections::HashMap;
use std::hash::Hash;

impl<K, V> InsertOrPanic<K, V> for HashMap<K, V>
where
    K: Eq + Hash,
{
    fn generic_insert_or_panic(&mut self, k: K, v: V) {
        use std::collections::hash_map::Entry;

        match self.entry(k) {
            Entry::Vacant(o) => o.insert(v),
            Entry::Occupied(_) => panic!("attempt to overwrite entry in dictionary"),
        };
    }
}

use std::collections::BTreeMap;

impl<K, V> InsertOrPanic<K, V> for BTreeMap<K, V>
where
    K: Ord,
{
    fn generic_insert_or_panic(&mut self, k: K, v: V) {
        use std::collections::btree_map::Entry;

        match self.entry(k) {
            Entry::Vacant(o) => o.insert(v),
            Entry::Occupied(_) => panic!("attempt to overwrite entry in dictionary"),
        };
    }
}

Обратите внимание, что границы реализации каждого из них различны (Hash + Eq против Ord)так что они довольно сильно отличаются друг от друга.

Я чувствую, что иду в неправильном направлении.Как решить эту проблему?

Я только начал изучать Rust, и некоторые из моих проблем могут выглядеть нереально и надуманными, но я ищу способы решения проблем

Вы не предоставили достаточно информации, чтобы оправдать свои потребности, поэтому я оспариваю это утверждение.Как правило, вам не нужно быть общим для двух типов карт, поскольку проблемная область естественным образом тяготеет к одной или другой.

0 голосов
/ 08 июня 2018

Вы можете создать эту черту

trait Map<K: Hash + Eq, V> {
    fn contains_key<Q>(&self, k: &Q) -> bool;
    where
        K: Borrow<Q>,
        Q: Hash + Eq + Ord + ?Sized,

    fn insert(&mut self, k: K, v: V) -> Option<V>;
}

, а затем просто написать свой универсальный insert_or_panic для использования contains_key и insert вместо API входа.

Однако, естьтолько два типа карт, и их ключи требуют разных вещей, в частности, BTreeMap требует упорядоченных ключей.Это похоже на случай, когда написание универсальной функции, а не двух функций, является излишним.

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