问题在于iter() (docs) 返回一个“非消耗”迭代器,它分发对基础值 ([1]) 的引用。新的 HashMap 不能使用引用 (&String) 构造,它需要值 (String)。
在您的示例中,some_conversion 似乎为值部分返回了一个新的String,因此将.clone() 应用于键就可以了:
let old: HashMap<String, Value> = some_origin();
let new: HashMap<String, String> = old.iter().map(|(key, value)| {
return (key.clone(), some_conversion(value));
// ^---- .clone() call inserted
}).collect();
Here 是 rust 操场上完整示例的链接。
查看编译器 [2] 的错误消息,这确实很难弄清楚。我认为对此最有帮助的是围绕 Rust 中的引用和所有权建立一种直觉,以了解引用何时正常以及何时需要拥有的值。
虽然我建议阅读 Rust 书籍中关于引用和所有权的部分,甚至更多 Rust 编程,但要点如下:
- 通常,Rust 中的值只有一个所有者(例外是明确的共享所有权指针,例如
Rc)。
- 当一个值“按值”传递时,它被移动到新位置。这会使值的原始所有者无效。
- 一个值可以有多个共享引用,但是当任何共享引用存在时,该值是不可变的(不能存在或创建可变引用,因此不能修改或移动它)。
- 我们不能将值移出共享引用(这会使原始所有者无效,当共享引用存在时它是不可变的)。
- 通常,Rust 不会自动复制(用 Rust 的说法是“克隆”)值,即使它可以。相反,它拥有价值的所有权。 (例外是“
Copy”类型,复制成本很低,例如i32)。
- (此处不相关)也可以有一个对值的可变引用。虽然此可变引用退出,但无法创建共享引用。
这有什么帮助?
- 谁拥有哈希映射中的键?哈希映射可以(规则 1)!
- 但是我们如何将新的键值对放入哈希映射中呢?这些值被移动到哈希映射中(规则 2)。
- 但我们不能离开共享参考...(规则 3 + 规则 4)
- Rust 不想克隆值,除非我们告诉它这样做(规则 5)
- ...所以我们必须自己克隆它。
我希望这能给你一些直觉(我再次强烈推荐 Programming Rust)。一般来说,如果你做了一些有价值的事情,你要么获得它的所有权,要么得到一个参考。如果您取得所有权,则无法再使用拥有所有权的原始变量。如果您获得参考,则不能将所有权交给其他人(无需克隆)。而且 Rust 不会为你克隆。
[1]:文档称之为“以任意顺序访问所有键值对的迭代器。迭代器元素类型为 (&'a K, &'a V)。”忽略'a生命周期参数,可以看到元素类型为(&K, &V)。
[2]:
13 | .collect();
| ^^^^^^^ value of type `std::collections::HashMap<std::string::String, std::string::String>` cannot be built from `std::iter::Iterator<Item=(&std::string::String, std::string::String)>`
|
= help: the trait `std::iter::FromIterator<(&std::string::String, std::string::String)>` is not implemented for `std::collections::HashMap<std::string::String, std::string::String>`