我有一个字符串迭代器thread_ts
,它是从stdin中获得的
curl https://slack.com/api/chat.postMessage -X POST -H 'Content-type: application/json; charset=utf-8' -H "Authorization: Bearer TOKEN" --data '{"channel":"CHANNEL-ID", "text":"curl", "thread_ts":"THREAD-TS"}'
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());
还有其他干净的方法可以做到这一点吗?
答案 0 :(得分:1)
在示例代码中,lines
是对从stdin
获得的读取器读取的行进行迭代的迭代器。如您所说,它将返回String
个实例,但您没有将它们存储在任何地方。
std::string::String::split_whitespace
的定义如下:
pub fn split_whitespace(&self) -> SplitWhitespace
因此,它引用了一个字符串-它不使用该字符串。它返回一个迭代器,该迭代器生成字符串切片&str
-引用字符串的一部分,但不拥有它。
实际上,一旦您完成传递给flat_map
的闭包,没有人拥有它,因此将其删除。这将使&str
产生的words
悬空,从而产生错误。
一种解决方案是将这些行收集到一个向量中,如下所示:
let lines: Vec<String> = stdin.lock().lines().map(|l| l.unwrap()).collect();
let words = lines.iter().flat_map(|l| l.split_whitespace());
String
实例保存在Vec<String>
中,该实例可以继续存在,以便&str
产生的words
可以引用。
如果有很多行,并且您不想将它们全部保留在内存中,则您可能希望一次执行一行:
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<String>
并将每个单词复制到其中的开销。
您可能一直希望零拷贝实现,它消耗了Strings
产生的lines
。我认为可以通过创建一个split_whitespace()
函数来创建String
所有权并返回拥有该字符串的迭代器来创建该函数。