如何更新可变 HashMap 中的值?
Posted
技术标签:
【中文标题】如何更新可变 HashMap 中的值?【英文标题】:How can I update a value in a mutable HashMap? 【发布时间】:2015-08-05 12:32:50 【问题描述】:这是我想要做的:
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
但这会引发错误:
Rust 2015
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>`
Rust 2018
error[E0594]: cannot assign to data in a `&` reference
--> src/main.rs:8:5
|
8 | my_map["a"] += 10;
| ^^^^^^^^^^^^^^^^^ cannot assign
我不太明白这意味着什么,因为我将 HashMap
设置为可变的。当我尝试更新 vector
中的元素时,我得到了预期的结果:
let mut my_vec = vec![1, 2, 3];
my_vec[0] += 10;
println! ":?", my_vec;
// [11, 2, 3]
HashMap
与我收到上述错误有何不同?有没有办法更新值?
【问题讨论】:
【参考方案1】:我将分享我自己的答案,因为我遇到了这个问题,但我正在使用 Structs,所以在我的情况下,这种方式有点棘手
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);
你可以在Rust Playground上玩这个
【讨论】:
【参考方案2】:考虑:
let mut m = std::collections::HashMap::new();
m.insert("a", 1);
m.insert("b", 3);
let k = "c";
如果密钥已经存在:
m.insert(k, 10 + m[k] );
如果密钥不存在:
-
您可以更新键的值:
m.insert(k, 10 + if m.contains_key(k) m[k] else 0 );
-
或仅在密钥不存在时才插入密钥:
m.entry(k).or_insert(0);
m.insert(k, 200 + m[k]);
-
或者更新一个密钥,防止密钥可能没有被设置:
*m.entry(k).or_insert(0) += 3000;
最后打印值:
println!("", m[k]); // 3210
见:https://doc.rust-lang.org/std/collections/struct.HashMap.html
【讨论】:
【参考方案3】:不可变索引和可变索引由两个不同的特征提供:分别为Index
和IndexMut
。
目前HashMap
没有实现IndexMut
,而Vec
does。
The commit that removed HashMap
's IndexMut
implementation 状态:
此提交删除了 HashMap 和 BTreeMap 上的 IndexMut impls,在 为了防止 API 最终包含 IndexSet 特征。
据我了解,假设的 IndexSet
特征将允许您为 HashMap
分配全新的值,而不仅仅是读取或改变现有条目:
let mut map = HashMap::new();
map["key"] = "value";
目前,您可以使用get_mut
:
*my_map.get_mut("a").unwrap() += 10;
或者entry
API:
*my_map.entry("a").or_insert(42) += 10;
【讨论】:
IndexMut 预计会在未来实施吗? @LukeDupin 表示怀疑。取而代之的是假设的IndexSet
特征。
*my_map.entry("a").or_insert(42) += 10;
那*有什么作用?取消引用哪一部分?
@Eftekhari 带括号:(*(my_map.entry("a").or_insert(42))) += 10;
@GermanFaller let tmp = my_map.entry("a").or_insert(some_default); tmp.a += 1; tmp.b += 2
.以上是关于如何更新可变 HashMap 中的值?的主要内容,如果未能解决你的问题,请参考以下文章