[英]Why are the values in a given HashMap mutable when I don't believe I have explicitly declared them as such?
我为 The Book 的第 8.3 节中的第三个建议练习写了一个可行的解决方案,但其中一些行为违背了我的直觉。 具体来说,我似乎能够改变一个看起来被实例化为不可变的向量。
我已经包含了我认为相关的代码部分,省略了不与存储在HashMap
中的Vec
交互的代码部分。
我在代码块之后进行了一些猜测,但我真的可以对实际发生的事情进行更可靠的解释。
// Start by declaring a new HashMap. This is where the mystery begins for me.
let mut departments: HashMap<String, Vec<String>> = HashMap::new();
// This code deals with getting user input from stdin and has been elided
// ...
// Match the first string slice
match args[0] {
// Add an employee to a department in the HashMap
"add" => {
// POINT OF INTEREST 1
// Adding a department that isn't already in the HashMap will cause a new empty
// vector to be inserted at the newly created key
let list = departments.entry(args[2].to_string()).or_insert(Vec::new());
// In any case, we insert the employee's name into the vector associated with
// whatever department we got from stdin
list.push(args[1].to_string());
}
// List employees
"who" => match args[1] {
// List all employees in every department, employees shown in alphabetical order
"all" => {
for (department, employees) in &mut departments {
// POINT OF INTEREST 2
// Why am I allowed to sort this vector? The artifact underlying the reference
// was never explicitly made mutable.
employees.sort();
for ee in employees {
println!("{}: {}", department, ee);
}
}
}
// List all employees in a given department, employees shown in alphabetical order
dept => {
let employees = departments.get_mut(dept);
match employees {
Some(entries) => {
// POINT OF INTEREST 3
// This one is seems the least mysterious to me, since I get the value
// of the HashMap at `dept` through `.get_mut()`.
println!("{}:", dept);
entries.sort();
for ee in entries {
println!("\t{}", ee);
}
}
_ => (),
}
}
}
}
假设 1:在POINT OF INTEREST 1
处,我对.or_insert()
的调用返回对新向量的可变引用,这就是为什么稍后对 HashMap 工作中的值调用.sort()
的原因。
这似乎不是可能的答案,一开始,我声明departments
的类型为HashMap<String, Vec<String>>
,而不是HashMap<String, &mut Vec<String>>
。
假设 2:当我声明departments
是可变的时,它的键和值继承了这种可变性。 这似乎也不太可能,因为在我(非常有限的)经验中没有任何迹象表明这样的事情是 Rust 的一个特性。 我也喜欢认为,如果在本书的前 8 章中明确说明了这一点,它会引起我的注意,但众所周知,我以前会略过重要的细节。
for (department, employees) in &mut departments {
for
循环利用了这个IntoIter
实现:
impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> {
type Item = (&'a K, &'a mut V);
}
由于这种实现,当您遍历&mut HashMap<K, V>
时,您会得到(&K, &mut V)
的元组。 请注意,键是不可变借用的,而值是可变的。 这使您可以修改值,因为employees
的类型是&mut Vec<String>
。
为什么 map 能够返回可变引用? map 同时拥有键和值,因此它可以根据需要返回对其中任何一个的可变引用。 这就是拥有者的意义:如果这是您的特权,您可以让其他人可变地借用您的物品。
HashMap
很乐意让您改变值,因为这不会影响数据结构。 它不允许您修改密钥,因为这会更改它们的哈希值并使它们在 hash 表中的存储位置无效。 HashMap
可以返回&mut K
。 借阅检查员不会阻止它。 但它不会,因为调用者可能会破坏 hash map。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.