我需要保护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"),
};
}
现在我想概括它以使用任何类型的地图:
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,我的一些问题可能看起来不切实际和牵强附会,但我正在寻找解决问题的方法,而不是解决问题,或至少知道限制语言。
常见问题解答explains高等级的类型可以解决这个问题,但这是一个很大的特点,因此生锈需要仔细处理。
答案 0 :(得分:0)
您可以创建此特征
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
而不是Entry API。
但是,只有两种类型的地图,它们的键需要不同的东西,特别是BTreeMap
需要有序的键。这听起来像写一个通用函数而不是两个函数的情况是过度的。
答案 1 :(得分:0)
是时候进入另一个特质吗?
是。没有人需要这个特殊的通用表达式,所以你可以自己抽象出来。
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,我的一些问题可能看起来不切实际和牵强附会,但我正在寻找解决问题的方法
您尚未提供足够的信息来证明您的需求,因此我要对此声明提出质疑。通常,您不需要在两种类型的地图上使用通用,因为问题域自然会倾向于其中一种。