Коллекция типа `i32` не может быть собрана из` std :: iter :: Iterator` - PullRequest
0 голосов
/ 21 сентября 2019

Сегодня я пытаюсь решить проблему на LeetCode .Это мой код ( Детская площадка ):

#[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 голосов
/ 21 сентября 2019

В операторе [(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::<i32>() каждый раз, когда вы его анализируете, так что гораздо проще просто сделать это один раз наверху.Вы также можете проанализировать year, так как вам все равно понадобится сделать это ниже.После этих изменений вы не захотите снова анализировать day и year, поэтому удалите все операторы .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 функции.)

Я понимаю, что задание просит вас вернуться i32, но так как это вычисление может быть неудачным, было бы гораздо лучше вернуть Option<i32> (или еще лучше Result<i32, Error>, где Error - это некоторое описание возможных путей, которые могут пойти не так),Это будет работать лучше всего, если вы также последуете предложению выше, чтобы разделить его на две функции.Затем вы можете проанализировать и проверить дату в первой функции, а затем с учетом правильной даты вычислить день года.Это позволит вам удалить все вызовы unwrap (и явную панику, которую я предложил).Зная, что ваша функция не паникует, это приятное чувство.

Наконец, в этом коде много повторений, так что вы можете быть в состоянии вычленить вещи и не повторять себя так много.Например, вместо двух операторов сопоставления в зависимости от того, является ли это високосным годом или нет, просто укажите одно совпадение и добавьте одно, если это високосный год.Вы также можете указать количество дней в каждом месяце в массиве, например [31, 28, 31, 30, ...].Затем вы можете просто использовать номер месяца и сложить соответствующее количество дней.

(также очень маленький спор: проблема указывает на то, что он использует григорианский календарь, который не имеет особых случаев для прыжкалет, кратных 3200 или 172 800)

0 голосов
/ 21 сентября 2019

Вам не нужно перебирать кортеж и вообще вызывать collect.Он создает коллекцию, но ваша цель - всего одно значение i32.Существует фиксированный код: Playground

Я также заранее проанализировал значения и добавил ветку _ в matche es, потому что она должна быть исчерпывающей.В идеале вам также не нужно match.

Обновление: более короткая версия того же кода: https://play.rust -lang.org /? Version = stable & mode = debug & edition = 2018 & gist = a9a344c64f42332eb26f2a68fa260f72

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...