HashMap中的默认可变值

10

假设我有一个 HashMap,我想要获取一个条目的可变引用,或者如果该条目不存在,我想要一个新对象的可变引用,我该怎么做?我尝试使用 unwrap_or(),类似于这样:

fn foo() {
    let mut map: HashMap<&str, Vec<&str>> = HashMap::new();

    let mut ref = map.get_mut("whatever").unwrap_or( &mut Vec::<&str>::new() );

    // Modify ref.
}

但这行不通,因为Vec的生命周期不够长。有没有办法告诉Rust我希望返回的Vecfoo()具有相同的生命周期?我的意思是有一种显然的解决方案,但我觉得应该有更好的方法:

fn foo() {
    let mut map: HashMap<&str, Vec<&str>> = HashMap::new();

    let mut dummy: Vec<&str> = Vec::new();
    let mut ref = map.get_mut("whatever").unwrap_or( &dummy );

    // Modify ref.
}

5
您希望在任何时候都不向映射表中插入“虚拟”值来完成此操作吗?只是想问一下。 - bluss
确切地说,虽然在我的特定用例中只是一种偏好,但我可以想象有些情况下你可能不想插入dummy - Timmmm
2个回答

15

正如Shepmaster所提到的,这是使用输入模式的一个例子。一开始看起来有点啰嗦,但这样可以避免分配一个你可能不需要的数组,除非你真的需要它。我相信你可以围绕这个例子编写一个通用函数以减少冗余代码:)

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

fn foo() {
    let mut map = HashMap::<&str, Vec<&str>>::new();
    let mut result = match map.entry("whatever") {
       Vacant(entry) => entry.insert(Vec::new()),
       Occupied(entry) => entry.into_mut(),
    };

    // Do the work
    result.push("One thing");
    result.push("Then another");
}

我刚刚发现,这也可以缩写为or_insert

use std::collections::HashMap;

fn foo() {
    let mut map = HashMap::<&str, Vec<&str>>::new();
    let mut result = map.entry("whatever").or_insert(Vec::new());

    // Do the work
    result.push("One thing");
    result.push("Then another");
}

4
使用or_insert是较为简短的方式(示例)。 - Shepmaster

6
如果您想将您的dummy添加到map中,那么这是如何正确使用HashMap::entry?使用模式匹配添加到HashMap时,一次获取多个可变借用(或任何有关entry API的问题)的副本。
如果您不想添加它,则您的代码很好,您只需要按照编译器错误消息修复它。您正在尝试使用关键字作为标识符(ref),并且您需要获得可变引用以访问dummy& mut dummy):
use std::collections::HashMap;

fn foo() {
    let mut map: HashMap<&str, Vec<&str>> = HashMap::new();

    let mut dummy: Vec<&str> = Vec::new();
    let f = map.get_mut("whatever").unwrap_or( &mut dummy );
}

fn main() {}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接