在 Rust 的 HashMap 中返回精确值

12

我找不到一种合适的方法在 Rust 的 HashMap中精确返回键的值。所有现有的get方法返回的格式与精确格式不同。


4
欢迎来到StackOverflow!不幸的是,您的问题并不十分清晰明了。您能否稍微澄清一下呢?您所说的“确切格式”是什么意思?您是指确切类型吗?如果您能提供一小段代码片段,这将有助于我们了解您认为应该有效但实际上无效的代码 :) - Lukas Kalbertodt
不确定问题是否已经被编辑,但对我来说它非常有意义。 - zero_cool
2
问题在于“格式”一词使问题不清晰且含糊。HashMap<T>.get(k)返回一个Option<&T>。如果问题的作者想要问为什么值被包装在Option中,那么现有的答案似乎很好地回答了这个问题。如果发帖人想要问为什么返回值的是对该值的引用,则需要另一个答案。但是,如果问题没有更多的明确性,我们无法确定正在被问到的是哪些事情。 - jbg
2个回答

11

你可能想要使用HashMap::remove方法 - 它会从映射中删除该键并返回原始值而不是引用:

use std::collections::HashMap;

struct Thing {
    content: String,
}

fn main() {
    let mut hm: HashMap<u32, Thing> = HashMap::new();
    hm.insert(
        123,
        Thing {
            content: "abc".into(),
        },
    );
    hm.insert(
        432,
        Thing {
            content: "def".into(),
        },
    );

    // Remove object from map, and take ownership of it
    let value = hm.remove(&432);

    if let Some(v) = value {
        println!("Took ownership of Thing with content {:?}", v.content);
    };
}
get 方法必须返回对象的引用,因为原始对象只能存在于一个位置(它是由 HashMap 拥有的)。remove 方法可以返回原始对象(即 "拥有所有权"),因为它将其从原始所有者中删除。
另一种解决方案,取决于具体情况,可能是获取引用,对其调用 .clone() 以创建对象的副本(在这种情况下,它不起作用,因为我们的 Thing 示例对象未实现 Clone - 但如果值是例如 String,则会起作用)。
最后值得注意的是,在许多情况下仍然可以使用对象的引用 - 例如,通过获取引用可以完成上一个示例:
use std::collections::HashMap;

struct Thing {
    content: String,
}

fn main() {
    let mut hm: HashMap<u32, Thing> = HashMap::new();
    hm.insert(
        123,
        Thing {
            content: "abc".into(),
        },
    );
    hm.insert(
        432,
        Thing {
            content: "def".into(),
        },
    );

    let value = hm.get(&432); // Get reference to the Thing containing "def" instead of removing it from the map and taking ownership

    // Print the `content` as in previous example.
    if let Some(v) = value {
        println!("Showing content of referenced Thing: {:?}", v.content);
    }
}

3
有两种基本方法可以获取给定键的值:get()get_mut()。如果您只想读取值,请使用第一种方法;如果您需要修改值,请使用第二种方法:
fn get(&self, k: &Q) -> Option<&V>
fn get_mut(&mut self, k: &Q) -> Option<&mut V>

从它们的签名中可以看出,这两种方法返回的都是Option而不是直接的值。原因是给定的键可能没有与之关联的值:

use std::collections::HashMap;

let mut map = HashMap::new();
map.insert(1, "a");
assert_eq!(map.get(&1), Some(&"a")); // key exists
assert_eq!(map.get(&2), None);       // key does not exist

如果您确定地图包含给定的键,则可以使用 unwrap() 来获取选项中的值:
assert_eq!(map.get(&1).unwrap(), &"a");

然而,一般来说,考虑到键可能不存在的情况会更好(也更安全)。例如,您可以使用模式匹配

if let Some(value) = map.get(&1) {
    assert_eq!(value, &"a");
} else {
    // There is no value associated to the given key.
}

7
我认为问题在于返回的是一个引用,而非一个值。 - Zelphir Kaltstahl

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