Простая реализация для получения итератора первого слова каждой строки ввода - PullRequest
0 голосов
/ 18 мая 2019

Мне нужен итератор, который передает первое буквенное слово каждой строки реализации Read. Этот итератор:

  • Возвращает ошибку, если чтение ввода не удалось
  • Возвращает итератор строк, каждая из которых представляет алфавитное слово
  • игнорирует пустые строки или первые слова, содержащие символы, отличные от [a-zA-Z]

Я в итоге получил следующую реализацию ( тест здесь ):

fn get_first_words<'a>(r: &'a mut impl Read) -> impl Iterator<Item = Result<String>> + 'a {
    BufReader::new(r).lines().filter_map(|rline| {
        match rline.map(|line| {
            line.split_whitespace()
                .next()
                .filter(|word| word.chars().all(char::is_alphabetic))
                .map(&str::to_string)
        }) {
            Err(e) => Some(Err(e)),
            Ok(Some(w)) => Some(Ok(w)),
            Ok(None) => None,
        }
    })
}

Это отлично работает, но оказалось сложнее, чем я ожидал. В этой реализации есть вложенные итераторы, и было некоторое жонглирование типов, чтобы сохранить Result в качестве типа переноса при фильтрации по содержащимся значениям.

Может ли это быть написано проще, с менее вложенной логикой и с меньшим количеством жонглирования типов?

1 Ответ

1 голос
/ 18 мая 2019

Вы можете заменить выражение match на Result::transpose().Я бы также предложил разделить функцию, возвращающую первое слово, чтобы сделать код более читабельным.Наконец, вам не нужно принимать &'a mut impl Read - вместо этого будет работать и просто impl Read, поскольку существует реализация перенаправления , которая реализует Read для &mut impl Read.Вместе упрощенный код может выглядеть следующим образом:

fn first_word(s: String) -> Option<String> {
    s.split_whitespace()
        .next()
        .filter(|word| word.chars().all(char::is_alphabetic))
        .map(From::from)
}

fn get_first_words(r: impl Read) -> impl Iterator<Item = Result<String>> {
    BufReader::new(r)
        .lines()
        .filter_map(|line| line.map(first_word).transpose())
}

Редактировать: Использование impl Read вместо &mut impl Read приведет к перемещению изменяемых ссылок в функцию, а не к неявному повторному заимствованию, поэтому, возможно, это не такВ конце концов, это хорошая идея, так как будет сложно запоминать их явно при необходимости.

...