更新可变HashMap中的值

Aka*_*all 44 hashmap rust

这是我想要做的:

use std::collections::HashMap;

fn main() {
    let mut my_map = HashMap::new();
    my_map.insert("a", 1);
    my_map.insert("b", 3);

    my_map["a"] += 10;
    // I expect my_map becomes {"b": 3, "a": 11}
}
Run Code Online (Sandbox Code Playgroud)

引发以下错误:

error[E0594]: cannot assign to immutable indexed content
 --> src/main.rs:8:5
  |
8 |     my_map["a"] += 10;
  |     ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
  |
  = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, i32>`
Run Code Online (Sandbox Code Playgroud)

我真的不明白这意味着什么,因为我做了HashMap可变的.当我尝试更新a中的元素时vector,我得到了预期的结果:

error[E0594]: cannot assign to data in a `&` reference
 --> src/main.rs:8:5
  |
8 |     my_map["a"] += 10;
  |     ^^^^^^^^^^^^^^^^^ cannot assign
Run Code Online (Sandbox Code Playgroud)

有什么不同HashMap我得到上述错误?有没有办法更新价值?

She*_*ter 71

可变索引和可变索引由两个不同的特征提供:IndexIndexMut.

目前,HashMap并没有实现IndexMut,而Vec.

提交该删除HashMapIndexMut执行状态:

此提交将删除HashMap和BTreeMap上的IndexMut impls,以便针对最终包含的IndexSet特征进行面向未来的证明.

我的理解是,假设IndexSet特征允许您为a分配全新的值HashMap,而不仅仅是读取或改变现有条目:

let mut map = HashMap::new();
map["key"] = "value";
Run Code Online (Sandbox Code Playgroud)

目前,您可以使用get_mut:

*my_map.get_mut("a").unwrap() += 10;
Run Code Online (Sandbox Code Playgroud)

entryAPI:

*my_map.entry("a").or_insert(42) += 10;
Run Code Online (Sandbox Code Playgroud)

  • @LukeDupin表示怀疑.取而代之的是假设的"IndexSet"特征将被实现. (3认同)
  • @Eftekhari 添加了括号: `(*(my_map.entry("a").or_insert(42))) += 10;` (3认同)
  • IndexMut预计将来会实施吗? (2认同)
  • `*my_map.entry("a").or_insert(42) += 10;` 这有什么作用?取消引用哪一部分? (2认同)

was*_*mup 14

考虑:

let mut m = std::collections::HashMap::new();
m.insert("a", 1);
m.insert("b", 3);
let k = "c";
Run Code Online (Sandbox Code Playgroud)

如果密钥已经存在:

    m.insert(k, 10 + m[k] );
Run Code Online (Sandbox Code Playgroud)

如果密钥不存在:

  1. 您可以更新键的值:
    m.insert(k, 10 + if m.contains_key(k) { m[k] } else { 0 });
Run Code Online (Sandbox Code Playgroud)
  1. 或者,仅当它不存在时才首先插入一个键:
    m.entry(k).or_insert(0);
    m.insert(k, 200 + m[k]);
Run Code Online (Sandbox Code Playgroud)
  1. 或者更新一个密钥,防止密钥可能没有被设置:
    *m.entry(k).or_insert(0) += 3000;
Run Code Online (Sandbox Code Playgroud)

最后打印值:

    println!("{}", m[k]); // 3210
Run Code Online (Sandbox Code Playgroud)

请参阅:https :
//doc.rust-lang.org/std/collections/struct.HashMap.html


Ger*_*ler 6

我将分享我自己的答案,因为我遇到了这个问题,但我正在使用结构,所以,在我的情况下,这种方式有点棘手

use std::collections::HashMap;

#[derive(Debug)]
struct ExampleStruct {
    pub field1: usize,
    pub field2: f64,
}

fn main() {
    let mut example_map = HashMap::new();
    &example_map.insert(1usize, ExampleStruct { field1: 50, field2: 184.0});
    &example_map.insert(6usize, ExampleStruct { field1: 60, field2: 486.0});

    //First Try
    (*example_map.get_mut(&1).unwrap()).field1 += 55; //50+55=105
    (*example_map.get_mut(&6).unwrap()).field1 -= 25; //60-25=35

    //Spliting lines
    let op_elem = example_map.get_mut(&6);
    let elem = op_elem.unwrap();
    (*elem).field2 = 200.0;

    let op_ok_elem = example_map.get_mut(&1);
    let elem = op_ok_elem.unwrap_or_else(|| panic!("This msg should not appear"));
    (*elem).field2 = 777.0;

    println!("Map at this point: {:?}", example_map);
    let op_err_elem = example_map.get_mut(&8);
    let _elem = op_err_elem.unwrap_or_else(|| panic!("Be careful, check you key"));

    println!("{:?}", example_map);
}
Run Code Online (Sandbox Code Playgroud)

你可以在Rust Playground上玩这个


小智 6

你可以这样做.and_modify

let mut my_map = HashMap::new();
my_map.insert("a", 1);
my_map.entry("a").and_modify(|k| *k += 10);
assert_eq!(my_map[&"a"], 11);
Run Code Online (Sandbox Code Playgroud)