【问题标题】:A collection of type `i32` cannot be built from `std::iter::Iterator<Item=_>`不能从 `std::iter::Iterator<Item=_>` 构建类型为 `i32` 的集合
【发布时间】:2019-09-21 17:17:37
【问题描述】:

今天我尝试解决LeetCode 上的一个问题。这是我的代码 (Playground):

#[test]
fn basic_test() {
    assert_eq!(day_of_year("2019-01-09".to_string()), 9);
    assert_eq!(day_of_year("2019-02-10".to_string()), 41);
    assert_eq!(day_of_year("2003-03-01".to_string()), 60);
    assert_eq!(day_of_year("2004-03-01".to_string()), 61);
}

pub fn day_of_year(date: String) -> i32 {
    let vec: Vec<&str> = date.split("-").collect();
    [(vec[0],vec[1],vec[2])].iter().map(|(year,month,day)|
        match month {
            &"01" => day.parse().unwrap(),
            &"02" => day.parse().unwrap() + 31,
            _ => match year.parse().unwrap(){
                y if y%4==0&&y%100!=0 
                    ||y%400==0&&y%3200!=0 
                    ||y%172800==0=>
                        match month {
                            &"03" => day.parse().unwrap()+31+29,
                            &"04" => day.parse().unwrap()+31+29+31,
                            &"05" => day.parse().unwrap()+31+29+31+30,
                            &"06" => day.parse().unwrap()+31+29+31+30+31,
                            &"07" => day.parse().unwrap()+31+29+31+30+31+30,
                            &"08" => day.parse().unwrap()+31+29+31+30+31+30+31,
                            &"09" => day.parse().unwrap()+31+29+31+30+31+30+31+31,
                            &"10" => day.parse().unwrap()+31+29+31+30+31+30+31+31+30,
                            &"11" => day.parse().unwrap()+31+29+31+30+31+30+31+31+30+31,
                            &"12" => day.parse().unwrap()+31+29+31+30+31+30+31+31+30+31+30
                        },
                _ => match month{
                        &"03" => day.parse().unwrap()+31+28,
                        &"04" => day.parse().unwrap()+31+28+31,
                        &"05" => day.parse().unwrap()+31+28+31+30,
                        &"06" => day.parse().unwrap()+31+28+31+30+31,
                        &"07" => day.parse().unwrap()+31+28+31+30+31+30,
                        &"08" => day.parse().unwrap()+31+28+31+30+31+30+31,
                        &"09" => day.parse().unwrap()+31+28+31+30+31+30+31+31,
                        &"10" => day.parse().unwrap()+31+28+31+30+31+30+31+31+30,
                        &"11" => day.parse().unwrap()+31+28+31+30+31+30+31+31+30+31,
                        &"12" => day.parse().unwrap()+31+28+31+30+31+30+31+31+30+31+30
                }
            }
        }
    ).collect()
}

我认为代码可以自我解释。我收到此错误消息:

error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `_`
  --> src/lib.rs:45:7
   |
45 |     ).collect()
   |       ^^^^^^^ a collection of type `i32` cannot be built from `std::iter::Iterator<Item=_>`
   |
   = help: the trait `std::iter::FromIterator<_>` is not implemented for `i32`

我尝试将其更改为collect::&lt;Vec&lt;i32&gt;&gt;[0]。但仍然得到编译错误。让我知道如何更改代码以使其编译。

【问题讨论】:

  • 您好,这里有一些关于如何在 SO 上提出更好问题的快速提示。 (a) “我认为代码可以自我解释。” -> 用几句话解释它永远不会有坏处。 (b) 将完整的代码和完整的错误消息添加到您的帖子中(就像我现在为您所做的那样)。 (c) 告诉我们您对错误的什么不了解。 (d) 发帖前尽量简化代码,搜索词minimal reproducible example。一般来说:表现出你关心,否则你不能指望别人关心。

标签: rust


【解决方案1】:

您根本不需要遍历元组并调用collect。它创建了一个集合,但您的目标只是一个 i32 值。有固定代码:Playground

我还提前解析了值,并在matchees 中添加了_ 分支,因为它应该是详尽的。理想情况下,您也不需要match

更新:相同代码的更短版本:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a9a344c64f42332eb26f2a68fa260f72

【讨论】:

    【解决方案2】:

    在语句[(vec[0],vec[1],vec[2])].iter() 中,您创建一个包含一个元素的(固定长度)数组,然后立即对其进行迭代。您使用的唯一迭代器方法是map,因此简单地使用它可能会更惯用

    let year = vec[0];
    let month = vec[1];
    let day = vec[2];
    

    然后从那里继续而不使用map。更好的是,您可以借此机会将day 解析为整数,而不必解析匹配语句的每个分支。这也将解决您遇到的无法推断 day 解析为的类型的问题。每次解析它时都必须写day.parse::&lt;i32&gt;(),所以在顶部写一次要容易得多。您也可以解析year,因为无论如何您都需要在下面执行此操作。在这些更改之后,您将不想再次解析 dayyear,因此删除它们上的所有 .parse().unwrap() 语句。

    let year: i32 = vec[0].parse().unwrap();
    let month = vec[1];
    let day: i32 = vec[2].parse().unwrap();
    

    之后,编译器建议的更改应该足以让它工作。您不再需要将month 匹配为&amp;&amp;str(例如&amp;"01"),因为您没有创建&amp;str 的数组并迭代其中的引用(在您的原始代码中,最好使用into_iter() 而不是iter() 来避免这种情况)。此外,编译器会告诉您month 上的匹配并不详尽。您需要添加一个包罗万象的分支,以防输入与任何其他分支都不匹配。我建议在匹配语句的末尾使用 _ =&gt; panic!("Invalid month") 之类的内容。


    只是一些额外的提示可以让您的代码看起来更好。命令cargo fmt(这个工具也存在于操场上的“工具”下)将自动将您的代码格式化为更惯用的样式。总的来说,这只会使阅读更容易。我还建议运行cargo clippy(也可以在操场上使用)来捕获任何可能的错误并使您的代码更加地道。在这种情况下,clippy 提出了一些小建议。

    只是一个一般性的编码技巧,我还将这个函数分成一个解析日期的函数和一个查找一年中第几天的函数。这样你就不需要同时做这两件事,而且更容易思考。 (这不太符合挑战提供给您的格式,因此您必须从 day_of_year 函数内部调用此解析函数。

    我了解挑战要求您返回 i32,但由于这是一个可能失败的计算,因此返回 Option&lt;i32&gt; 会更好(或者更好的是 Result&lt;i32, Error&gt;,其中 @987654347 @ 是对可能出错的方式的一些描述)。如果您也按照上面的建议将其分成两个函数,这将最有效。然后你可以在第一个函数中解析和验证日期,然后给定一个有效的日期,计算一年中的哪一天。这将使您删除所有unwrap 调用(以及我建议的显式恐慌)。知道你的函数不会恐慌是一种很好的感觉。

    最后,这段代码有很多重复,所以你可以把事情排除在外,不要重复太多。例如,不是根据是否是闰年而有两个匹配语句,而只需一个匹配项,如果是闰年则添加一个匹配项。您可能还希望在[31, 28, 31, 30, ...] 之类的数组中包含每个月的天数。然后你可以只使用月份数字并将适当的天数相加。

    (另外,一个非常小的问题:问题指定它使用公历,对于闰年没有特殊情况,3,200 或 172,800 的倍数)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 2020-04-20
      • 1970-01-01
      • 2020-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多