我希望将这段Python代码转换成Rust:
for line in sys.stdin:
do something to the whole line including \n
但是我只能找到读取单个完整行(包括 \n
)的示例,或者不读取 \n
的示例。
看起来这应该是世界上最简单的事情之一,但我找不到它。
我希望将这段Python代码转换成Rust:
for line in sys.stdin:
do something to the whole line including \n
但是我只能找到读取单个完整行(包括 \n
)的示例,或者不读取 \n
的示例。
看起来这应该是世界上最简单的事情之一,但我找不到它。
无论是Python还是Rust,都提供了方便的API来迭代文件中的行,它们只是在方便性与完整性之间做出了不同的权衡。Rust选择了额外的便利,并剥离了换行符,以便能够区分最后一行是否以终止符结束。Python则选择了相反的方式,以所有行解析器必须考虑最后的\n
为代价,同时还必须考虑它是可选的。
但是BufRead::lines()
只是一个方便的API;如果它不能满足您的需求,您可以随时降到更低级别的read_line()
方法:
let mut line = String::new();
while input.read_line(&mut line)? != 0 {
let line = std::mem::take(&mut line);
// ...
}
如果您在多个地方使用此类代码,或者只是想要一个for
循环的便利性,您可以将其抽象为返回迭代器的实用函数,例如:
fn full_lines(mut input: impl BufRead) -> impl Iterator<Item = io::Result<String>> {
std::iter::from_fn(move || {
let mut vec = String::new();
match input.read_line(&mut vec) {
Ok(0) => None,
Ok(_) => Some(Ok(vec)),
Err(e) => Some(Err(e)),
}
})
}
然后你可以使用类似于Python中的for
循环:
for line in full_lines(io::stdin().lock()) {
let line = line?;
// ...
}
通过额外的努力,甚至可以使full_lines
成为实现了BufRead
的任何内容的方法:
trait FullLines: BufRead + Sized {
fn full_lines<'a>(self) -> Box<dyn Iterator<Item = io::Result<String>> + 'a>
where
Self: 'a,
{
Box::new(full_lines(self))
}
}
// Provide a blanket implementation of FullLines for any T
// that implements BufRead
impl<T: BufRead> FullLines for T {}
// Usage:
use FullLines;
for line in io::stdin().lock().full_lines() {
let line = line?;
// ...
}
"".to_string()
来创建缓冲区,而不是直接使用 String::new()
呢? - harmicread_line
返回读取的字节数,因此您还可以将while
条件替换为input.read_line(&mut line)? > 0
。聪明地使用了take
,我从未想过这样使用它。 - trentwhile
条件也立即返回新行的实验,这样用户就不必在每次循环迭代结束时记得重置它,类似于这样。使用 mem::take()
的版本要简单得多,但是不必要的测试仍然来自于一个版本,其中我会丢弃 read_line
返回值。 - user4815162342
lines()
,它不会包括终止符\n
。 - user4815162342while(<>)
或 Python 的for i in sys.stdin
)。 - Ole Tange