【问题标题】:Correct answer at rustlings course, but not happy with it在 rustlings 课程中正确答案,但不满意
【发布时间】:2023-01-28 04:05:26
【问题描述】:

这是对 niveaus 的最高抱怨,但我解决了 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 结构中。我尝试不使用它,但它不起作用(借用东西)并使用 &amp; 但它不高兴,因为它期望 String - 而不是 &amp;String

【问题讨论】:

    标签: string rust hashmap


    【解决方案1】:

    不确定什么不能正常工作?您可以移至第二个使用站点,它工作正常:

            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,因为您拥有哈希映射键,所以它并不真正有价值。尽管此时您不再有 Team 结构,所以它可能应该重命名,例如ScoreGoals(您可以去掉左边两个成员的前缀)。

    【讨论】:

      【解决方案2】:

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

      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
      }
      

      【讨论】:

      • 将数据结构的标识符(在本例中为团队名称)用作键并存储在数据结构本身中的情况并不少见。所以,他们做到了不是奇怪地设置哈希图。
      【解决方案3】:

      学到东西了!谢谢!

      顺便说一句,我有一个后续问题:与 Rust book 相比,为什么我们不能在这一行添加 (*)

      team_1.goals_scored += team_1_score;
      

      成为

      *team_1.goals_scored += team_1_score;
      

      失败的任何原因?

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

      【讨论】:

      • 如果您有新问题,请点击 按钮提问。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
      【解决方案4】:

      关于后续问题,您是否尝试过以下操作:

      (*team_1).goals_scored += team_1_score;
      

      【讨论】:

        猜你喜欢
        • 2022-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-30
        • 1970-01-01
        • 1970-01-01
        • 2016-08-17
        • 1970-01-01
        相关资源
        最近更新 更多