[英]How to combine std::str::lines and std::io::lines?
I want to write a function to parse text, but the text may come from external file or an internal &str
. 我想编写一个函数来解析文本,但文本可能来自外部文件或内部
&str
。 The parse
function may go like this: parse
函数可能如下所示:
fn parse(lines: GenericLinesGenerator) {
for line in lines {
// parse content
}
}
... and it can be invoked like this: ......它可以像这样调用:
use std::io::BufReader;
use std::fs::File;
let fin = BufReader::new(File::open("info.txt").expect("not found"));
parse(TransformFromIO(fin.lines()))
or 要么
let content: &'static str = "some\nlong\ntext";
parse(TransformFromStr(content.lines()))
Is it possible to implement such a parse
function? 是否可以实现这样的
parse
功能?
The two iterators don't produce the same values: 这两个迭代器不会产生相同的值:
impl<B: BufRead> Iterator for io::Lines<B> {
type Item = Result<String>;
}
impl<'a> Iterator for str::Lines<'a> {
type Item = &'a str;
}
You have to handle that difference somehow. 你必须以某种方式处理这种差异。 The most important difference is that
io::Lines
can fail . 最重要的区别是
io::Lines
可能会失败 。 Your program has to decide how to deal with that; 你的程序必须决定如何处理; I've chosen to just abort the program.
我选择了中止该计划。
The next thing you need to do is to accept any type that can be converted into an iterator, and the value yielded from the iterator has to be converted to a type that you can deal with. 接下来你需要做的是接受任何可以转换为迭代器的类型,并且必须将迭代器产生的值转换为你可以处理的类型。 It appears that
&str
is the common denominator. 似乎
&str
是共同点。
This is solved by using IntoIterator
and Borrow
: 这可以通过使用
IntoIterator
和Borrow
来解决:
use std::borrow::Borrow;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
fn parse<I>(lines: I)
where
I: IntoIterator,
I::Item: Borrow<str>,
{
for line in lines {
println!("line: {}", line.borrow());
}
}
fn main() {
parse("alpha\nbeta\ngamma".lines());
println!("----");
let f = File::open("/etc/hosts").expect("Couldn't open");
let b = BufReader::new(f);
parse(b.lines().map(|l| l.expect("Bad line!")));
}
Check The Rust Programming Language section on where
clauses for more information about trait bounds . 有关特征边界的更多信息,请参阅
where
子句 的Rust编程语言部分。
Using the Borrow
bound in the parse
function will allow you to borrow &str
, but if you need String
values, a better approach is to use Cow
. 使用
parse
函数中的Borrow
bound将允许你借用&str
,但是如果你需要String
值,更好的方法是使用Cow
。
Using line.borrow().to_string()
to obtain a String
value will always allocate, even when parse
is called with lines from file (in this case, lines.map
produces String
). 使用
line.borrow().to_string()
获取String
值将始终分配,即使用文件中的行调用parse
(在这种情况下, lines.map
生成String
)。
Using line.into_owned()
will allocate when called with lines from an &str
, but will not allocate when called with lines from file (will just unwrap the String
value passed to Cow::Owned
). 当使用来自
&str
行调用时,将使用line.into_owned()
进行分配,但是当使用来自文件的行调用时将不会分配(将仅解包传递给Cow::Owned
的String
值)。
use std::borrow::Cow;
use std::io::{BufReader, BufRead};
use std::iter::IntoIterator;
use std::fs::File;
fn parse<'a, I>(lines: I)
where I: IntoIterator,
I::Item: Into<Cow<'a, str>>
{
for line in lines {
let line: Cow<'a, str> = line.into();
let line: String = line.into_owned();
// or
let line = line.into().into_owned()
println!("{}", line);
}
}
fn main() {
let fin = BufReader::new(File::open("/etc/hosts").expect("cannot open file"));
parse(fin.lines().map(|r| r.expect("file read failed")));
let content: &'static str = "some\nlong\ntext";
parse(content.lines());
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.