繁体   English   中英

当我不相信我已经明确声明它们时,为什么给定 HashMap 中的值是可变的?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM