首页 > 解决方案 > Recursive impl Extend for HashMap<_, HashSet<_>> 在哪里组合集合,而不是覆盖?

问题描述

我正在尝试使我的代码适应我之前的问题的解决方案。基本上,我有一个HashMap<String, HashSet<String>>应该由人造丝的par_extend 生成。问题是键重复,在这种情况下,我希望HashSets 被组合,而不是被覆盖。换句话说,有没有办法在impl Extend此处添加自定义,以便以下代码正确执行?

use std::collections::{HashMap, HashSet};

fn main() {
    let mut d: HashMap<String, HashSet<String>> = HashMap::new();

    d.extend(vec![1, 2].iter().map(|x| {
        let mut z = HashSet::new();
        z.insert(x.to_string());
        return ("a".into(), z);
    }));

    assert_eq!(d.get("a").unwrap().len(), 2);
}

标签: multithreadingrustrayon

解决方案


由于孤儿规则,你不能。但是,您可以定义一个廉价的包装器,Extend为该包装器实现,进行扩展,然后再次打开原始地图。也许是这样的:

use std::collections::{HashMap, HashSet};

type MapOfSets = HashMap<String, HashSet<String>>;

fn main() {
    let mut d: ExtendWrapper = ExtendWrapper::new(HashMap::new());

    d.extend(vec![1, 2].iter().map(|x| {
        let mut z = HashSet::new();
        z.insert(x.to_string());
        return ("a".into(), z);
    }));
    
    let d = d.into_inner();

    assert_eq!(d.get("a").unwrap().len(), 2);
}

struct ExtendWrapper(MapOfSets);

impl ExtendWrapper {
    fn new(map: MapOfSets) -> Self {
        Self(map)
    }

    fn into_inner(self) -> MapOfSets {
        self.0
    }
}

impl Extend<(String, HashSet<String>)> for ExtendWrapper {
    fn extend<T>(&mut self, iter: T)
    where T: IntoIterator<Item = (String, HashSet<String>)>
    {
        for (key, set) in iter {
            // lifetimes make it infeasible to use the entry api here :(
            if let Some(s) = self.0.get_mut(&key) {
                s.extend(set);
                continue;
            }
            self.0.insert(key, set);
        }
    }
}

操场


推荐阅读