如何在Rust中创建和使用字符串到字符串的Hashmap?

37

我应该如何在Rust中惯用地创建一个字符串到字符串的哈希映射?以下代码可以工作,但这是正确的方法吗?我是否应该使用不同类型的字符串?

use std::collections::hashmap::HashMap;
//use std::str;
fn main() {
        let mut mymap = HashMap::new();
        mymap.insert("foo".to_string(), "bar".to_string());
        println!("{0}", mymap["foo".to_string()]);
}

1
需要使用拥有所有权的字符串吗?你可以使用&'static str(字符串字面量)来做吗,特别是对于键值? - Chris Morgan
2个回答

34

假设你需要String的灵活性,那么HashMap<String, String>是正确的选择。另一个选择是&str,但这会对HashMap的使用方式/传递方式施加重大限制;但如果它能工作,将一个或两个参数更改为&str将更有效率。这个选择应由您需要什么样的所有权语义和字符串有多动态决定,有关详细信息请参见该回答字符串指南

顺便说一句,在HashMap<String, ...>中搜索String可能很昂贵:如果您没有,则需要分配一个新的String。我们有一个解决方法,即通过find_equiv形式来传递字符串字面值(更一般地说,任何&str)而不分配新的String:

use std::collections::HashMap;
fn main() {
    let mut mymap = HashMap::new();
    mymap.insert("foo".to_string(), "bar".to_string());
    println!("{}", mymap.find_equiv(&"foo"));
    println!("{}", mymap.find_equiv(&"not there"));
}

playpen(注意我在返回值中保留了Option,可以调用.unwrap()或适当处理缺少的键)。

另一个稍微不同的选项(在某些情况下更通用,在其他情况下不太通用)是std::string::as_string函数,它允许将&str中的数据视为&String,而无需分配内存(正如名称所示)。它返回一个可以被解引用为String的对象,例如:

use std::collections::HashMap;
use std::string;

fn main() {
    let mut mymap = HashMap::new();
    mymap.insert("foo".to_string(), "bar".to_string());
    println!("{}", mymap[*string::as_string("foo")]);
}

playpen

(类似的还有一个 std::vec::as_vec。)


MaybeOwned(http://doc.rust-lang.org/std/str/enum.MaybeOwned.html)能否在这里提供一些灵活性?它似乎可以用作键? - Matthieu M.
@MatthieuM 那是另一种方法,没错。 - huon
7
我理解您的意思是:“我假设 find_equiv() 不再需要了?您的 Playpen 示例不再编译,而且我没有在 HashMap 上看到 find_equiv 方法。” - dimo414
8
find_equiv()已被弃用,现在使用Borrow特性替代。在使用HashMap的get/contains/remove方法时,&str&String之间的转换现在会自动执行。可在此链接中查看代码演示。 - Tey'
使用&str在HashMap上会有哪些“重要限制”? - undefined
1
@Chad: 使用具有非'static生命周期的任何str的困难。如果完全使用具有'static生命周期的字面str作为键,那就没问题。但如果从现有的具有更有限生命周期的String派生这些键,你需要确保它们至少与HashMap一样长时间存活,这真是一件麻烦的事情。 - undefined

8

为了方便未来读者,我写下这篇答案。huon的回答在当时是正确的,但是*_equiv方法已经被清除

HashMap文档提供了一个使用String-String哈希表的示例,其中可以使用&str

以下代码将正常工作。不需要进行新的String分配:

use std::collections::HashMap;

fn main() {
    let mut mymap = HashMap::new();
    mymap.insert("foo".to_string(), "bar".to_string());
    println!("{0}", mymap["foo"]);
    println!("{0}", mymap.get("foo").unwrap());
}

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