如何使用从其他两个 HashMap 移动的值创建 HashMap?

ama*_*iny 7 hashmap rust

我有两个HashMap<&str, String>具有相同键的,我希望创建一个HashMap具有相同键的值组合在一起。我不想保留对前两个HashMaps 的引用,而是想将Strings移动到新的HashMap.

use std::collections::HashMap;

#[derive(Debug)]
struct Contact {
    phone: String,
    address: String,
}

fn main() {
    let mut phones: HashMap<&str, String> = HashMap::new();
    phones.insert("Daniel", "798-1364".into());
    phones.insert("Ashley", "645-7689".into());
    phones.insert("Katie", "435-8291".into());
    phones.insert("Robert", "956-1745".into());

    let mut addresses: HashMap<&str, String> = HashMap::new();
    addresses.insert("Daniel", "12 A Street".into());
    addresses.insert("Ashley", "12 B Street".into());
    addresses.insert("Katie", "12 C Street".into());
    addresses.insert("Robert", "12 D Street".into());

    let contacts: HashMap<&str, Contact> = phones.keys().fold(HashMap::new(), |mut acc, value| {
        acc.entry(value).or_insert(Contact {
            phone: *phones.get(value).unwrap(),
            address: *addresses.get(value).unwrap(),
        });
        acc
    });

    println!("{:?}", contacts);
}
Run Code Online (Sandbox Code Playgroud)

但我有一个错误

use std::collections::HashMap;

#[derive(Debug)]
struct Contact {
    phone: String,
    address: String,
}

fn main() {
    let mut phones: HashMap<&str, String> = HashMap::new();
    phones.insert("Daniel", "798-1364".into());
    phones.insert("Ashley", "645-7689".into());
    phones.insert("Katie", "435-8291".into());
    phones.insert("Robert", "956-1745".into());

    let mut addresses: HashMap<&str, String> = HashMap::new();
    addresses.insert("Daniel", "12 A Street".into());
    addresses.insert("Ashley", "12 B Street".into());
    addresses.insert("Katie", "12 C Street".into());
    addresses.insert("Robert", "12 D Street".into());

    let contacts: HashMap<&str, Contact> = phones.keys().fold(HashMap::new(), |mut acc, value| {
        acc.entry(value).or_insert(Contact {
            phone: *phones.get(value).unwrap(),
            address: *addresses.get(value).unwrap(),
        });
        acc
    });

    println!("{:?}", contacts);
}
Run Code Online (Sandbox Code Playgroud)

操场

tre*_*tcl 7

HashMap::get返回一个Option<&V>,即对地图内值的引用。您不能从 with 移出引用,*除非Vimplements Copy。您需要一种不同的方法来将值移出映射,即HashMap::remove(注意它返回Option<V>)。

如果您尝试使用 重写相同的算法remove,则会得到不同的错误:

    let contacts: HashMap<&str, Contact> = phones.keys().fold(HashMap::new(), |mut acc, value| {
        acc.entry(value).or_insert(Contact {
            phone: phones.remove(value).unwrap(),
            address: addresses.remove(value).unwrap(),
        });
        acc
    });
Run Code Online (Sandbox Code Playgroud)
    let contacts: HashMap<&str, Contact> = phones.keys().fold(HashMap::new(), |mut acc, value| {
        acc.entry(value).or_insert(Contact {
            phone: phones.remove(value).unwrap(),
            address: addresses.remove(value).unwrap(),
        });
        acc
    });
Run Code Online (Sandbox Code Playgroud)

这个错误告诉你在迭代数据结构时不能改变它,因为改变数据结构可能会使迭代器失效。有时您可以使用内部可变性来解决这个问题,但在这种情况下,您不需要做任何类似的事情。只需phones.into_iter()在迭代时调用即可将电话号码移出地图。然后很容易使用 amap来创建(&str, Contact)元组,最后,collect它全部回到HashMap.

    let contacts: HashMap<_, _> = phones
        .into_iter()
        .map(|(key, phone)| {
            (
                key,
                Contact {
                    phone,
                    address: addresses.remove(key).unwrap(),
                },
            )
        })
        .collect();
Run Code Online (Sandbox Code Playgroud)

操场

  • 我自己喜欢 [`flat_map` 版本](https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=ebab664c760d05b98ddd075895c1acab)。 (2认同)