我正在尝试读取多个文件,并且想从文件路径的向量创建流。我已经和编译器进行了一段时间的战斗,但不确定如何使它起作用:
fn formatted_tags_stream(
args: &[&str],
files: &Vec<PathBuf>,
) -> Result<impl Iterator<Item = String>> {
// Transform list of paths into a list of files
let files: Vec<File> = files.into_iter().map(|f| File::open(f)).flatten().collect();
// Here is where I'm stuck :/
let stream =
files
.into_iter()
.skip(1)
.fold(BufReader::new(files[0]), |acc, mut f| acc.chain(f));
Ok(BufReader::new(stream).lines().filter_map(|line| {
line.ok().and_then(|tag| {
if let Ok(tag) = serde_json::from_str::<TagInfo>(&tag) {
Some(tag.format())
} else {
None
}
})
}))
}
最佳答案
如果使用fold
,则该函数必须始终返回相同的类型。但是,如果在编写时使用它,则该函数将采用F
类型并在第一遍中返回Chain<F, ...>
。下一遍将需要采用Chain<F, ...>
并返回Chain<Chain<F, ...>, ...>
-导致“每次迭代的类型不同”。这将不起作用,因为Rust想要知道确切的类型,并且该类型必须保持不变。
但是,您可以键入内容并将其隐藏在指针后面(即Box
,添加“特质对象”)。参见here (I did some minor adjustments to make it compile):
use std::path::PathBuf;
use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::io::BufRead;
fn formatted_tags_stream(
args: &[&str],
files: &Vec<PathBuf>,
) -> Result<impl Iterator<Item = String>, ()> {
// Transform list of paths into a list of files
let files: Vec<File> = files.into_iter().map(|f| File::open(f)).flatten().collect();
// Here is where I'm stuck :/
let bufreader = Box::new(std::io::empty()) as Box<dyn Read>;
let stream =
files
.into_iter()
.fold(bufreader, |acc, f| Box::new(acc.chain(f)) as Box<dyn Read>);
Ok(BufReader::new(stream).lines().filter_map(|line| {
line.ok().and_then(|tag| {
if let Ok(_tag) = tag.parse::<usize>() {
Some(tag)
} else {
None
}
})
}))
}
请注意,使用Box<dyn Read>
会导致一些运行时开销,因为它会导致动态分配。
关于rust - 如何从文件向量创建单个流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64439679/