为何我的Rust HashMap or_insert更新结构体无需解引用即可生效?
关于Rust HashMap中Entry返回值的解引用困惑
根据Rust官方文档中的示例,下面代码里的count变量必须通过解引用(*)才能正常工作:
let text = "hello world wonderful world"; let mut map = HashMap::new(); for word in text.split_whitespace() { let count = map.entry(word).or_insert(0); *count += 1; } println!("{:?}", map);
但我自己写的代码里,在HashMap找到对应键后更新结构体中的u8类型变量(team_val.goals_scored)时,不需要解引用就能正常运行。我本来以为更新HashMap中的结构体内容时必须解引用,这让我很困惑。
我的代码:
#[derive(Debug)] struct Team { name: String, goals_scored: u8, goals_conceded: u8, } fn build_scores_table(results: String) -> HashMap<String, Team> { // 球队名称作为键,对应的结构体作为值 let mut scores: HashMap<String, Team> = HashMap::new(); for r in results.lines() { let v: Vec<&str> = r.split(',').collect(); let team_1_name = v[0].to_string(); let team_1_score: u8 = v[2].parse().unwrap(); let team_2_name = v[1].to_string(); let team_2_score: u8 = v[3].parse().unwrap(); // 从当前行提取数据填充分数表:team_1的进球数是team_2的失球数,反之亦然 let mut team_1_struct= Team { name: team_1_name.clone(), goals_scored: team_1_score, goals_conceded: team_2_score }; let mut team_2_struct= Team { name: team_2_name.clone(), goals_scored: team_2_score, goals_conceded: team_1_score }; if scores.contains_key(&team_1_name) { let team_val = scores.entry(team_1_name.clone()).or_insert(team_1_struct); println!("Yooo {:#?}",team_val); team_val.goals_scored +=team_1_score; team_val.goals_conceded += team_2_score; } else { scores.insert(team_1_name,team_1_struct); } if scores.contains_key(&team_2_name) { let team_val = scores.entry(team_2_name.clone()).or_insert(team_2_struct); println!("Yooo {:#?}",team_val); team_val.goals_scored +=team_2_score; team_val.goals_conceded += team_1_score; } else { scores.insert(team_2_name,team_2_struct); } } scores }
原因解释
这两种情况的核心区别在于**entry().or_insert()返回的引用类型,以及Rust的自动解引用规则**:
官方文档示例中,
or_insert(0)返回的是&mut i32(对整数的可变引用)。+=运算符需要直接操作i32值本身,因此必须显式解引用这个引用,才能让运算符作用到底层的整数上。你的代码中,
or_insert(team_1_struct)返回的是&mut Team(对结构体的可变引用)。当你通过team_val.goals_scored访问结构体字段时,Rust会自动触发自动解引用(Deref coercion),帮你省略掉显式的*操作——team_val.goals_scored等价于(*team_val).goals_scored,因此无需手动解引用就能直接修改结构体内部的字段。
简单总结:
- 对基本类型的可变引用执行赋值/运算时,需要显式解引用
- 对结构体/枚举的可变引用访问字段时,Rust会自动完成解引用,无需手动添加
*
内容的提问来源于stack exchange,提问作者WowBow
相关产品推荐
相关产品推荐

