rust - 获取每行输入第一个单词的迭代器的简单实现

标签 rust iterator

我需要一个迭代器来流式传输 Read 实现的每一行的第一个字母单词。这个迭代器:

  • 如果读取输入失败则返回错误
  • 返回一个字符串迭代器,每个字符串代表一个字母单词
  • 忽略包含 [a-zA-Z]
  • 以外字符的空字符串或第一个单词

我最终得到了以下实现(test here):

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 保持为包装类型。

是否可以将其编写得更简单,使用更少的嵌套逻辑和更少的类型转换?

最佳答案

您可以用 Result::transpose() 替换您的 match 表达式.我还建议拆分返回第一个单词的函数,以使代码更具可读性。最后,您不需要接受 &'a mut impl Read – 只需接受 impl Read 也可以,因为有一个 forwarding implementation。为 &mut impl Read 实现 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 将导致可变引用被移动到函数中而不是被隐式地重新借用,所以这可能不是一个好主意毕竟,因为记住在必要时明确地重新借用它们会让人感到困惑。

关于rust - 获取每行输入第一个单词的迭代器的简单实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56195957/

相关文章:

rust - 对闭包中 ref 关键字的使用感到困惑

c - 为什么将堆分配的结构从 Rust 传递到 C 时,我的整数值发生了变化?

python - Python中迭代器的最后N个元素以外的所有元素

c++ - 为链表构建迭代器类(错误 : no matching constructor for initialization)

java - C++ 迭代器模型与 Java 迭代器模型

vector - 消耗向量的 Vec::chunks() 的替代方法

postgresql - 在 Diesel 中执行正确的联接

rust - 调用一个借用为不可变的闭包时,不能在循环中借用为可变的吗?

rust - 如何使用 log4rs 的 RollingFileAppender 合并滚动日志记录?

python - 迭代 N 个符号的所有 L 长度序列,其中包括所有 N 个符号