如何将 HashMap 的值收集到向量中?
Posted
技术标签:
【中文标题】如何将 HashMap 的值收集到向量中?【英文标题】:How do I collect the values of a HashMap into a vector? 【发布时间】:2019-11-05 12:27:59 【问题描述】:我找不到将HashMap
的值收集到文档中的Vec
的方法。我有score_table: HashMap<Id, Score>
,我想把所有的Score
s 变成all_scores: Vec<Score>
。
我很想使用 values
方法 (all_scores = score_table.values()
),但它不起作用,因为 values 不是 Vec
。
我知道Values
实现了ExactSizeIterator
特征,但我不知道如何将迭代器的所有值收集到一个向量中,而无需手动编写一个 for 循环并将向量中的值一个接一个地推入。
我也尝试过use std::iter::FromIterator;
,但以如下内容结束:
all_scores = Vec::from_iter(score_table.values());
expected type `std::vec::Vec<Score>`
found type `std::vec::Vec<&Score>`
感谢Hash map macro refuses to type-check, failing with a misleading (and seemingly buggy) error message?,我改成了:
all_scores = Vec::from_iter(score_table.values().cloned());
它不会对cargo check
产生错误。
这是一个好方法吗?
【问题讨论】:
如果你想收藏,为什么不用collect
?
“这是一种好方法吗?” — 关于 Rust(和 C/C++)的一件事是您需要考虑数据的所有权.默认情况下会移动数据,这会更改所有者。如果您不希望所有者更改,则可以传递参考,也可以克隆原始数据。哪种方式“好”取决于您的用例:如果哈希图是数据的所有者,则可能在其他任何地方使用引用(即Vec<&Score>
)。但是,当所讨论的类型很小时,克隆通常是正确的做法。
【参考方案1】:
HashMap.into_values
将在值上返回一个拥有迭代器:
let all_scores: Vec<Score> = score_table.into_values().collect();
相比之下,HashMap.values
的迭代器不拥有并返回引用 (&Score
) 而不是值。
【讨论】:
【参考方案2】:如果您不再需要score_table
,您可以通过以下方式将Score
值的所有权转让给all_scores
:
let all_scores: Vec<Score> = score_table.into_iter()
.map(|(_id, score)| score)
.collect();
与@apetranzilla 的克隆方法相比,这种方法会更快并且消耗更少的内存。它还支持任何结构,不仅是实现Clone
的结构。
【讨论】:
【参考方案3】:Iterator.collect
方法是为这个特定任务设计的。你是对的,如果你想要一个实际值的向量而不是引用,你需要.cloned()
(除非存储类型实现Copy
,如原语),所以代码如下所示:
all_scores = score_table.values().cloned().collect();
在内部,collect()
只使用FromIterator
,但它也推断输出的类型。有时没有足够的信息来推断类型,因此您可能需要明确指定所需的类型,如下所示:
all_scores = score_table.values().cloned().collect::<Vec<Score>>();
【讨论】:
以上是关于如何将 HashMap 的值收集到向量中?的主要内容,如果未能解决你的问题,请参考以下文章