【问题标题】:Creating word iterator from line iterator从行迭代器创建单词迭代器
【发布时间】:2018-12-03 19:13:56
【问题描述】:

我有一个字符串迭代器lines,它是从标准输入获得的

use std::io::{self, BufRead};

let mut stdin = io::stdin();
let lines = stdin.lock().lines().map(|l| l.unwrap());

lines 迭代器产生String 类型的值,而不是&str。我想创建一个迭代输入单词而不是行的迭代器。看起来这应该是可行的,但我天真的尝试不起作用:

let words = lines.flat_map(|l| l.split_whitespace());

编译器告诉我,l 在被借用的同时被删除了,这是有道理的:

error[E0597]: `l` does not live long enough
 --> src/lib.rs:6:36
  |
6 |     let words = lines.flat_map(|l| l.split_whitespace());
  |                                    ^                  - `l` dropped here while still borrowed
  |                                    |
  |                                    borrowed value does not live long enough
7 | }
  | - borrowed value needs to live until here

还有其他干净的方法可以做到这一点吗?

【问题讨论】:

标签: rust iterator borrow-checker


【解决方案1】:

在您的示例代码中,lines 是从您从stdin 获得的阅读器读取的行的迭代器。正如你所说,它返回 String 实例,但你没有将它们存储在任何地方。

std::string::String::split_whitespace 是这样定义的:

pub fn split_whitespace(&self) -> SplitWhitespace

所以,它需要一个字符串的引用——它不消耗字符串。它返回一个迭代器,该迭代器产生字符串切片&str - 它引用字符串的一部分,但不拥有它。

事实上,一旦你传递给flat_map 的闭包完成了,没有人拥有它,所以它被丢弃了。这将使words 产生的&str 悬空,从而导致错误。

一种解决方案是将线条收集到一个向量中,如下所示:

let lines: Vec<String> = stdin.lock().lines().map(|l| l.unwrap()).collect();

let words = lines.iter().flat_map(|l| l.split_whitespace());

String 实例保存在Vec&lt;String&gt; 中,它可以继续存在,以便words 产生的&amp;str 可以参考。

如果有很多行,并且您不想将它们全部保存在内存中,您可能更愿意一次写一行:

let lines = stdin.lock().lines().map(|l| l.unwrap());

let words = lines.flat_map(|l| {
    l.split_whitespace()
        .map(|s| s.to_owned())
        .collect::<Vec<String>>()
        .into_iter()
});

这里每一行的单词都被收集成一个Vec,一次一行。权衡是减少了整体内存消耗,而不是为每一行构造一个 Vec&lt;String&gt; 并将每个单词复制到其中的开销。

您可能一直希望零拷贝实现,它消耗了lines 产生的Strings。我认为可以通过创建一个 split_whitespace() 函数来创建 String 的所有权并返回一个拥有该字符串的迭代器。

【讨论】:

  • std::string::String::split_whitespace 有点误导,因为split_whitespace() 实际上是原始str 类型的固有方法。 &amp;String 通过 deref 强制转换为 &amp;str
猜你喜欢
  • 2016-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多