有没有更简洁或者说明性的方法来初始化 HashMap?

我使用 HashMap来计算字符串中不同字符的出现次数:

let text = "GATTACA";
let mut counts: HashMap<char, i32> = HashMap::new();
counts.insert('A', 0);
counts.insert('C', 0);
counts.insert('G', 0);
counts.insert('T', 0);


for c in text.chars() {
match counts.get_mut(&c) {
Some(x) => *x += 1,
None => (),
}
}

有没有更简洁或声明性的方法来初始化 HashMap? 例如,在 Python 中,我会这样做:

counts = { 'A': 0, 'C': 0, 'G': 0, 'T': 0 }

或者

counts = { key: 0 for key in 'ACGT' }
29201 次浏览

您可以使用迭代器来模拟字典理解,例如。

let counts = "ACGT".chars().map(|c| (c, 0_i32)).collect::<HashMap<_, _>>();

甚至是 for c in "ACGT".chars() { counts.insert(c, 0) }

此外,还可以编写一个宏来简洁地初始化任意值。

macro_rules! hashmap {
($( $key: expr => $val: expr ),*) => \{\{
let mut map = ::std::collections::HashMap::new();
$( map.insert($key, $val); )*
map
}}
}

就像 let counts = hashmap!['A' => 0, 'C' => 0, 'G' => 0, 'T' => 0];

我在 正式文件中看到的另一种方式是:

use std::collections::HashMap;


fn main() {
let timber_resources: HashMap<&str, i32> =
[("Norway", 100),
("Denmark", 50),
("Iceland", 10)]
.iter().cloned().collect();
// use the values stored in map
}

剪辑

当我再次访问官方文档时,我看到样本被更新(旧样本被删除)。下面是 Rust 1.56的最新解决方案:

let vikings = HashMap::from([
("Norway", 25),
("Denmark", 24),
("Iceland", 12),
]);

这个(非常常见的)场景就是为什么当我发现 Python 的 违约判决时,我听到了天使的歌声。 违约判决是一个字典,如果你试图得到一个字典中没有的密钥,立即 创造就是这个密钥的默认值,当你声明默认结果时,你会提供一个构造函数。所以,在 Python 中,你可以这样做:

counts = defaultdict(lambda: 0)
counts['A'] = counts['A'] + 1

对于计数事件,这是一种受欢迎的方法,因为当密钥空间很大或者程序员不知道密钥空间时,试图预先填充哈希表就会出现问题(想象一下,如果要计算提供给它的文本中的单词数量,就会出现问题)。你打算预先填充所有的英语单词吗?如果一个新单词进入词典怎么办?).

您可以在 Rust 中使用 选择类中不太为人所知的方法来实现同样的功能。说真的,当你有一些空闲时间的时候,只需要通读 选择中的所有方法。里面有一些非常方便的方法。

尽管没有处理简洁的初始化(这是 wsubject 所要求的) ,这里有两个答案(可以说,它们更适合于 OP 正在尝试做的事情)。

let text = "GATTACA";
let mut counts:HashMap<char,i32> = HashMap::new();
for c in text.chars() {
counts.insert(c,*(counts.get(&c).get_or_insert(&0))+1);
}

上面的方法使用 Option 的 获得或插入方法,如果它是 Some () ,则返回值,如果是 Nothing,则返回您提供的值。注意,即使这个方法名为 get _ or _ insert () ,它也是 < em > not 插入到散列表中; 这是 Option 的一个方法,散列表并不知道这个故障转移正在发生.不错的地方在于它为您打开了值的包装。这非常类似于 Python 的 defaultdict,不同之处在于您必须在代码中的多个位置提供默认值(引入 bug,但也提供了 defaultdict 所缺乏的附加灵活性)。

let text = "GATTACA";
let mut counts:HashMap<char,i32> = HashMap::new();
for c in text.chars() {
counts.insert(c,counts.get(&c).or_else(|| Some(&0)).unwrap()+1);
}

这种方法使用 Option 的 否则方法,它允许您指定一个 lambda 来生成值,并且,关键的是,它允许您 还是返回一个 Nothing (想象一下,如果您想检查散列表中的键,如果没有找到,那么检查 另一个散列表中的键,如果两者都没有找到,那么您生成一个 Nothing)。因为 否则返回了一个选项,所以我们必须使用 拆开包装(如果在 Nothing 上使用这个选项,就会引起恐慌,但是我们知道这里不适用)。

从 Rust 1.56开始,可以使用 from()从键-值对数组构建 Hashmap。这使得简洁地初始化成为可能,而不需要指定类型或编写宏。

use std::collections::HashMap;


fn main() {
let m = HashMap::from([
('A', 0),
('C', 0),
('G', 0),
('T', 0)
]);
}