问题历史
HashSet和HashMap是来自std::collections的标准结构,实现了基于哈希的快速查找。它们从语言的早期版本就内置于Rust中,但由于所有权系统,其内部使用细节常常使经验丰富的开发人员感到困惑。
问题
在插入和提取元素时(尤其是当值不是Copy时),在修改集合时(可变借用),以及在使用引用作为键时,会出现困惑。用户类型的Eq/Hash实现也存在问题。
解决方案
代码示例:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("key", 42); if let Some(value) = map.get("key") { println!("找到的值:{}", value); } }
关键特点:
可以对同一个HashMap的元素获取多个可变引用吗?
不可以,借用检查器不会允许这样做,以避免所有权的破坏。
可以直接使用字符串字面量"abc"作为HashMap<String, V>的键吗?
不可以,期望的是String,而"abc"是&'static str。需要转换:insert("abc".to_string(), val)。
可以从HashMap中提取值并将其保存在单独的变量中,然后继续使用HashMap吗?
可以,通过get获取值的引用——但如果进行remove(或移动提取),那么HashMap会变更,任何旧的引用都会变得无效。
尝试同时借用键和值,然后修改集合:
let mut map = HashMap::new(); map.insert("abc".to_string(), 10); let val = map.get("abc"); map.insert("def".to_string(), 20); // 借用检查器错误
优点:
缺点:
提取值,仅对其副本或克隆进行操作:
let mut map = HashMap::new(); map.insert("abc".to_string(), 10); if let Some(val) = map.get("abc") { let val = *val; // 复制 map.insert("def".to_string(), 20); // 一切正常 }
优点:
缺点: