rustlings课程的答案是正确的,但对此并不满意



这是最高级别的niveau的抱怨,但我解决了rustlings课程中的一项任务,我相信这不是最佳解决方案,甚至不是一个好的解决方案。

任务:https://github.com/rust-lang/rustlings/blob/main/exercises/hashmaps/hashmaps3.rs

我的解决方案(仅相关部分(:

fn build_scores_table(results: String) -> HashMap<String, Team> {
// The name of the team is the key and its associated struct is the value.
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();
let team_1 = scores.entry(team_1_name.clone()).or_insert(Team {
name: team_1_name.clone(),
goals_scored: 0,
goals_conceded: 0,
});
team_1.goals_scored += team_1_score;
team_1.goals_conceded += team_2_score;
let team_2 = scores.entry(team_2_name.clone()).or_insert(Team {
name: team_2_name.clone(),
goals_scored: 0,
goals_conceded: 0,
});
team_2.goals_scored += team_2_score;
team_2.goals_conceded += team_1_score;
}
scores
}

我的问题是,我正在.entry()方法内部和Team结构中克隆字符串(两次!(。我试着在没有的情况下使用它,但它不起作用(借用东西(,并使用&,但它并不高兴,因为它期望String而不是&String

不确定什么不起作用?你可以在第二个使用网站上移动,它运行良好:

let team_1 = scores.entry(team_1_name.clone()).or_insert(Team {
name: team_1_name,
goals_scored: 0,
goals_conceded: 0,
});
team_1.goals_scored += team_1_score;
team_1.goals_conceded += team_2_score;

如果你想在成功的情况下进行零克隆(团队已经有了条目(,代码就不那么性感了,但它也编译得很好:

if let Some(t) = scores.get_mut(&team_1_name) {
t.goals_scored += team_1_score;
t.goals_conceded += team_2_score;
} else {
scores.insert(team_1_name.clone(), Team {
name: team_1_name,
goals_scored: team_1_score,
goals_conceded: team_2_score,
});
}

从技术上讲,我们甚至可以删除初始to_string,在命中情况下不进行分配(显然,这意味着在未命中情况下进行两次分配(:

let team_1_name = v[0];
let team_1_score: u8 = v[2].parse().unwrap();
// ...
if let Some(t) = scores.get_mut(team_1_name) {
t.goals_scored += team_1_score;
t.goals_conceded += team_2_score;
} else {
scores.insert(team_1_name.to_string(), Team {
name: team_1_name.to_string(),
goals_scored: team_1_score,
goals_conceded: team_2_score,
});
}

或者,从Team结构中删除name,这并没有真正的价值,因为您有hashmap键。虽然在这一点上,您不再有Team结构,所以它可能应该重命名,例如ScoreGoals(您可以从剩下的两个成员中去掉前缀(。

您不需要第二个.clone()调用(在Team中(,因为您可以允许结构获得该调用的所有权,因为之后没有其他调用使用它。他们设置的哈希图对你来说有点奇怪,因为键和值都包含团队名称。如果您只是从结构定义中删除它,就不需要再进行克隆了(无论如何,它永远不会被使用(。

struct Team {
goals_scored: u8,
goals_conceded: u8,
}
fn build_scores_table(results: String) -> HashMap<String, Team> {
// The name of the team is the key and its associated struct is the value.
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();
let team_1 = scores.entry(team_1_name).or_insert(Team {
goals_scored: 0,
goals_conceded: 0,
});
team_1.goals_scored += team_1_score;
team_1.goals_conceded += team_2_score;
let team_2 = scores.entry(team_2_name).or_insert(Team {
goals_scored: 0,
goals_conceded: 0,
});
team_2.goals_scored += team_2_score;
team_2.goals_conceded += team_1_score;
}
scores
}

这就是我最终得到的结果,而不是疯狂地使用"和_ diffy";两次,但都是生活。

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();
scores.entry(team_1_name.clone())
.and_modify(|a| a.goals_scored += team_1_score)
.and_modify(|b| b.goals_conceded += team_2_score)
.or_insert(Team { name: team_1_name,
goals_scored: team_1_score,
goals_conceded: team_2_score });
scores.entry(team_2_name.clone())
.and_modify(|a| a.goals_scored += team_2_score)
.and_modify(|b| b.goals_conceded += team_1_score)
.or_insert(Team { name: team_2_name,
goals_scored: team_2_score,
goals_conceded: team_1_score });
}
scores
}

学习一些东西!非常感谢。

顺便说一句,我有一个后续问题:与《铁锈》一书相比,为什么我们不能在这行中添加(*(

team_1.goals_scored += team_1_score;

成为

*team_1.goals_scored += team_1_score;

它失败的原因是什么?

我认为这与作为hashmap值的是类型Team而不是基元类型这一事实有一定关系,但我仍然希望对此有一个清晰的理解。

关于后续问题,您尝试过以下方法吗:

(*team_1).goals_scored += team_1_score;

最新更新