无法从`std :: iter :: Iterator <Item = _>`构建类型为'i32'的集合。

时间:2019-09-21 17:17:37

标签: rust

今天,我尝试解决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::<Vec<i32>>[0]。但是仍然出现编译错误。让我知道如何更改代码以使其编译。

2 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分:0)

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

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

,然后从那里继续而不使用map。更好的是,您可以借此机会将day解析为整数,而不必在match语句的每个分支上进行解析。这还将解决您无法推断day解析为的类型的问题。每次解析时都必须编写day.parse::<i32>(),因此只需一次在顶部进行编写就容易得多。您也可以解析year,因为无论如何您都需要这样做。完成这些更改后,您将不想再次解析dayyear,因此请删除它们上的所有.parse().unwrap()语句。

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

此后,编译器建议的更改应足以使此功能生效。您不再需要将month匹配为&&str(例如&"01"),因为您无需创建&str的数组并遍历对其的引用(在原始版本中代码,最好使用into_iter()而不是iter()以避免这种情况)。此外,编译器会告诉您month上的匹配并不详尽。如果输入与任何其他分支都不匹配,则需要添加一个包罗万象的分支。我会在比赛声明的结尾建议_ => panic!("Invalid month")之类的东西。


仅需一些其他技巧,即可使您的代码看起来更好。命令cargo fmt(此工具也位于运动场上的“工具”下)将自动将代码格式化为更惯用的样式。总体来说,这使得阅读起来更加容易。我还建议运行cargo clippy(也可以在操场上找到)以捕获任何可能的错误并使您的代码更加习惯。在这种情况下,clippy提出了一些小建议。

只是一个通用的编码技巧,我还将该函数分为一个解析日期的函数和一个用于查找一年中的天数的函数。这样一来,您无需一次执行所有操作,而且考虑起来也更容易。 (这与挑战所提供的格式不太匹配,因此您必须从day_of_year函数内部调用此parse函数。)

我知道挑战会要求您返回i32,但是由于此计算可能会失败,因此最好返回Option<i32>(或者返回{{1 }},其中Result<i32, Error>是可能出错的一些描述)。如果您还按照上面的建议将其分为两个功能,则效果最好。然后,您可以在第一个函数中解析和验证日期,然后给定有效日期,计算一年中的日期。这将使您删除所有的Error调用(以及我建议的明确恐慌)。知道自己的功能不会感到惊慌。

最后,这段代码中有很多重复,因此您可能可以将事情排除在外,而不必重复太多。例如,根据是否是'年而不是具有两个match语句,而只有一个匹配项,如果是it年则添加一个。您可能还希望在unwrap之类的数组中每个月的天数。然后,您可以只使用月份数,然后加上适当的天数。

(也是一个很小的错误:问题表明它使用公历,对于,年没有特殊情况,为3,200或172,800的倍数)