HashMap
hashmap
hashmap是一个无序的字典
创建hashmap
new
创建空的hashmap
use std::collections::HashMap;
fn main() {
// let mut map = HashMap::<String, i32>::new();
let mut map:HashMap<String, i32> = HashMap::new();
println!("{:?}", map);
}
with_capacity
创建一个具有指定最小容量的空
HashMap
use std::collections::HashMap;
fn main() {
let mut map = HashMap::with_capacity(10);
for i in 1..=10 {
map.insert(i, i * 10);
};
println!("{:?}", map);
}
{6: 60, 2: 20, 7: 70, 8: 80, 1: 10, 4: 40, 10: 100, 9: 90, 3: 30, 5: 50}
from
支持数组转hashmap,如果是
Vec和Iterator需要使用collect转换
use std::collections::HashMap;
use std::ptr::hash;
fn main() {
let mut map = HashMap::from([("hello".to_string(), "world".to_string())]);
println!("map: {:?}", map);
let v: Vec<(&str, i32)> = vec![("a", 1), ("b", 2)];
let mut map2: HashMap<&str, i32> = v.into_iter().collect();
println!("map2: {:?}", map2);
}
map: {"hello": "world"}
迭代器创建hashmap
collect
use std::collections::HashMap;
use std::ptr::hash;
fn main() {
let v: Vec<(&str, i32)> = vec![("a", 1), ("b", 2)];
let mut map: HashMap<&str, i32> = v.into_iter().collect();
println!("map: {:?}", map);
}
map: {"b": 2, "a": 1}
zip
两个
vec压缩为Vec<(T, V)>,然后使用collect转为hashmap
use std::collections::HashMap;
fn main() {
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let map: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
println!("map: {:?}", map);
}
map: {"Yellow": 50, "Blue": 10}
所有权转移问题
实现
Copy特征,该类型会被复制进HashMap没实现
Copy特征,所有权将被转移给HashMap中
fn main() {
use std::collections::HashMap;
let name = String::from("Sunface");
let age = 18;
let mut map = HashMap::new();
map.insert(name, age);
println!("map: {:?}", map);
// name没有copy trait,所以无法使用
// println!("因为过于无耻,{}已经被从帅气男孩名单中除名", name);
println!("还有,他的真实年龄远远不止{}岁", age);
}
map: {"Sunface": 18}
还有,他的真实年龄远远不止18岁
使用引用类型
HashMap 中存储的引用类型,其指向的变量(被引用者)的生命周期必须严格大于 HashMap 本身的生命周期,否则会触发编译错误(悬垂引用)
fn main() {
use std::collections::HashMap;
let name = String::from("Sunface");
let age = 18;
let mut map = HashMap::new();
map.insert(&name, age);
// 删除name
drop(name);
// 报错
println!("map: {:?}", map);
}
插入值
insert
如果键已存在,会覆盖原有值,并返回被覆盖的旧值(
Option<V>);如果键不存在,返回None
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
let old_value = map.insert("a".to_string(), 1);
println!("old_value:{:?}", old_value); // None(首次插入无旧值)
// 重复插入同一键:覆盖旧值,返回旧值
let old_value2 = map.insert("a".to_string(), 10);
println!("old_value2:{:?}", old_value2); // Some(1)
}
old_value:None
old_value2:Some(1)
entry
处理键存不存在的方式,返回
Entry枚举的Occupied和Vacant两个变体
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("one", 1);
map.insert("two", 2);
let s = map.entry("one");
println!("{:?}", s);
let s = map.entry("one1");
println!("{:?}", s);
}
Entry(OccupiedEntry { key: "one", value: 1, .. })
Entry(VacantEntry("one1"))
显式匹配
需要使用
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
fn main() {
let mut map = HashMap::new();
map.insert("one", 1);
map.insert("two", 2);
// map中已经存在了one
let s = map.entry("one");
match s {
// 键存在
Entry::Occupied(mut occupied) => {
let k = occupied.get_mut();
*k += 1;
}
// 键不存在
Entry::Vacant(vacant) => {
vacant.insert(1);
}
}
// map中不存在ccc键
let s = map.entry("ccc");
match s {
// 键存在
Entry::Occupied(mut occupied) => {
let k = occupied.get_mut();
*k += 1;
}
// 键不存在
Entry::Vacant(vacant) => {
vacant.insert(1);
}
}
println!("{:?}", map);
}
{"one": 2, "ccc": 1, "two": 2}
Entry::Occupied值存在
- get_mut和into_mut区别
- get_mut仍可继续调用其他方法(如
get()、insert()) - into_mut无法再使用该
Occupied(已被消耗)
- get_mut仍可继续调用其他方法(如
| Occupied方法 | 作用 |
|---|---|
get(&self) |
获取现有值的不可变引用(&V),只能读不能改 |
get_mut(&mut self) |
获取现有值的可变引用(&mut V),可修改值 |
into_mut(self) |
消耗 OccupiedEntry,返回值的可变引用(&mut V) |
insert(&mut self, V) |
覆盖现有值,返回被替换的旧值(V) |
remove(self) |
移除该键值对,返回被移除的值(V) |
Entry::Vacant值不存在
| Vacant方法 | 作用 |
|---|---|
key(&self) |
获取待插入的键的不可变引用(&K)(仅能读键,无值可操作) |
into_key(self) |
消耗 VacantEntry,返回待插入的键的所有权(K) |
insert(self, V) |
插入指定值到空位,返回新插入值的可变引用(&mut V) |
insert_with<F>(self, f: F) |
通过闭包生成值并插入,返回新值的可变引用(&mut F::Output) |
entry()+or_insert()
如果key不存在就插入
如果key存在,返回对已有值的可变引用(
&mut V)底层就是
VacantEntry+ insert
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(String::from("a"), 1);
map.insert(String::from("b"), 2);
map.insert(String::from("c"), 3);
map.entry(String::from("d")).or_insert(4);
// 存在返回
let s = map.entry(String::from("a")).or_insert(11);
*s += 1;
println!("{:?}", map);
}
{"c": 3, "a": 2, "d": 4, "b": 2}
entry(key).or_default()
是
or_insert的特化版本。如果键不存在,则插入该类型的默认值(即实现Defaulttrait 的值,如0,"",Vec::new())。
use std::collections::HashMap;
fn main() {
let mut map:HashMap<&str, i32> = HashMap::new();
let s = "b,a,b,a,b,s,h,d";
for c in s.split(",") {
// let count = map.entry(c).or_default();
// *count += 1;
*map.entry(c).or_default() += 1;
}
println!("{:?}", map);
}
{"a": 2, "h": 1, "d": 1, "s": 1, "b": 3}
entry().and_modify().or_insert()
and_modify仅当键存在时操作值,相比操作Occupied,可以链式调用
相当于
Occupied + get_mut()
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.entry("key")
.and_modify(|e| *e += 5) // 存在时加 5
.or_insert(10); // 不存在时插入 10
println!("map: {:?}", map);
map.entry("key")
.and_modify(|e| *e *= 2) // 存在时乘以 2
.or_insert(20); // 不会执行(键已存在)
println!("map: {:?}", map);
}
map: {"key": 10}
map: {"key": 20}
entry()+or_insert_with()
和or_insert区别是,or_insert是立即创建值(饿汉式),or_insert_with是惰性创建值
- or_insert(V)
- 简单类型(如
i32、bool、&str),创建成本几乎为 0
- 简单类型(如
- or_insert_with(F)
- 创建成本高(比如
String、Vec、自定义结构体、需要计算 / IO 生成的值)
- 创建成本高(比如
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("s", 2);
// 键存在也会创建3
map.entry("s").or_insert(3);
// or_insert_with 键存在不会调用
map.entry("s").or_insert_with(|| {println!("创建了11"); 3});
map.entry("m").or_insert_with(|| {println!("创建了22"); 3});
println!("{:?}", map);
}
创建了22
{"m": 3, "s": 2}
删除key
remove
仅被移除的值(所有权);键不存在返回
None
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
let s1 = map.remove("a");
println!("s1: {:?}", s1);
let s2 = map.remove("aa");
println!("s2: {:?}", s2);
println!("map: {:?}", map);
}
s1: Some(1)
s2: None
map: {"b": 2}
remove_entry
被移除的键 + 值(所有权);键不存在返回
None
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
let s1 = map.remove_entry("a");
println!("s1: {:?}", s1);
let s2 = map.remove_entry("aa");
println!("s2: {:?}", s2);
println!("map: {:?}", map);
}
s1: Some(("a", 1))
s2: None
map: {"b": 2}
检查值是否存在
contains_key
返回bool值,检测值是否存在
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("s", 2);
// 键存在,不做任何事
// 键不存在,value设置3
map.entry("s").or_insert(3);
let s = map.contains_key("s");
println!("{:?}", s);
println!("{:?}", map);
}
true
{"s": 2}
获取所有key值
keys
借用 HashMap(
&self),不消耗map自身
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
let s: Vec<_> = map.keys().collect();
println!("{:?}", s);
}
["b", "c", "a"]
into_keys
消耗map,转移所有权
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
let s: Vec<_> = map.into_keys().collect();
println!("{:?}", s);
}
["c", "a", "b"]
获取所有value值
values
keys一样,获取引用,不消耗map
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
let s: Vec<_> = map.values().collect();
println!("{:?}", s);
println!("{:?}", map);
}
[1, 3, 2]
into_values
获取所有权,调用之后不能再使用map了
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
let s: Vec<_> = map.into_values().collect();
println!("{:?}", s);
}
[3, 1, 2]
判断是否是空字典is_empty
返回bool值
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
println!("{}", map.is_empty());
map.insert("a", 1);
map.insert("b", 2);
println!("{}", map.is_empty());
}
true
false
获取值
get
返回
Option<&V>,仅读取值,不修改,键不存在返回None
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
println!("{:?}", map.get("a"));
println!("{:?}", map.get("c"));
}
Some(1)
None
get_mut
返回
Option<&mut V>,需要修改已存在的值键,不存在返回None
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
if let Some(v) = map.get_mut("a") {
*v += 3
} else {
println!("a 不存在");
};
if let Some(v) = map.get_mut("c") {
*v += 3
} else {
println!("c 不存在");
};
println!("{:?}", map);
}
c 不存在
{"b": 2, "a": 4}
获取长度len
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
println!("{:?}", map.len());
}
2
创建迭代器
iter
只读遍历(无法修改值)
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
for (k, v) in map.iter() {
println!("k: {}, v: {}", k, v);
}
}
k: b, v: 2
k: a, v: 1
iter_mut
可修改值(键仍不可改)
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
for (k, v) in map.iter_mut() {
println!("k: {}, v: {}", k, v);
// 解引用修改value值
*v += 10;
};
println!("map: {:?}", map);
}
k: b, v: 2
k: a, v: 1
map: {"b": 12, "a": 11}

浙公网安备 33010602011771号