and_modify()
与 or_insert()
在 Rust
下有两个map
:BTreeMap
与 HashMap
。
我们日常在使用 map
的时候经常会遇到这样的情景:
let mut map = HashMap::new();
// ...
map[&key] += val;
在 C++
、Python
等等支持 map
结构的语言中,这样子的操作不会遇到任何问题,但是在Rust
中,这样的操作会有以下问题:
key
不一定存在在map
中。Rust
会对每个[]
操作做越界检查,因此map[&key]
其实是相当于C++
中的map.at(key)
map[&key]
得到的是一个immutable
的引用,不可以直接加上一个val
在之前,我一般使用这样的方式来解决这个问题:
if let Some(e) = map.get_mut(&key) {
*e += val;
} else {
map.insert(key, val);
}
这么写也能解决问题,但是很长,而且绕了几个弯子,很难一眼看出代码的意图。
在参考了 这个提问 后,我发现了几个好用的“彩蛋”:and_modify()
与 or_insert()
。
之所以说是彩蛋,是因为它藏得太隐蔽了。。。我在之前使用
clippy
处理我的代码的时候从未遇到过有关于此的提示。Rust 总是会有这样子的现象,你以为它缺少某个功能而不方便使用,但是其实它就在那里,得靠你自己去发现,然后它会告诉你,看,不是我不好用,只是你笨。Orz
这两个函数很好地解决了以上的问题:
map.entry(&key)
.and_modify(|e| *e += val)
.or_insert(val)
此外还有几个类似的函数:
or_default
,只对实现了Default trait
的值有用or_insert_with
,和or_insert
的区别是:or_insert
插入一个值,而or_insert_with
插入的是一个函数的返回值or_insert_with_kay
,在or_insert_with
的基础上,将key
作为函数的参数传入