Rust:如何合并迭代逻辑,创建Struct并收集为Result<Vec<MyStruct>,MyError>?
合并WalkDir迭代与自定义类型转换的Rust实现
原代码示例
假设你原本的代码结构如下(包含walker和rewalk函数):
use walkdir::{DirEntry, WalkDir, Error as WalkDirError}; use std::error::Error; #[derive(Debug)] struct MyStruct { path: String, is_file: bool, } #[derive(Debug)] enum MyError { WalkDir(WalkDirError), Conversion(String), } impl From<WalkDirError> for MyError { fn from(e: WalkDirError) -> Self { MyError::WalkDir(e) } } // 遍历目录并收集符合条件的DirEntry fn walker(path: &str) -> Result<Vec<DirEntry>, WalkDirError> { WalkDir::new(path) .into_iter() .filter_map(|entry| entry.ok()) .filter(|entry| entry.file_type().is_file()) .collect() } // 转换DirEntry为MyStruct fn rewalk(entries: Vec<DirEntry>) -> Result<Vec<MyStruct>, MyError> { let mut result = Vec::new(); for entry in entries { let path = entry.path().to_str() .ok_or_else(|| MyError::Conversion("Invalid UTF-8 path".to_string()))? .to_string(); let is_file = entry.file_type().is_file(); result.push(MyStruct { path, is_file }); } Ok(result) }
重构后的合并实现
通过迭代器链式调用,直接在遍历过程中完成筛选和类型转换,最终返回Result<Vec<MyStruct>, MyError>:
use walkdir::{DirEntry, WalkDir, Error as WalkDirError}; use std::error::Error; #[derive(Debug)] struct MyStruct { path: String, is_file: bool, } #[derive(Debug)] enum MyError { WalkDir(WalkDirError), Conversion(String), } impl From<WalkDirError> for MyError { fn from(e: WalkDirError) -> Self { MyError::WalkDir(e) } } // 合并遍历与转换逻辑的函数 fn walk_and_convert(path: &str) -> Result<Vec<MyStruct>, MyError> { WalkDir::new(path) .into_iter() // 将WalkDir的错误转换为自定义MyError .map(|entry| entry.map_err(MyError::from)) // 筛选符合条件的条目(示例:仅保留文件) .filter(|entry| { // 若条目是错误则保留,最终collect会返回该错误;若想跳过错误可改用filter_map entry.as_ref().map_or(true, |e| e.file_type().is_file()) }) // 将DirEntry转换为MyStruct,处理转换中的错误 .map(|entry| { entry.and_then(|e| { let path = e.path().to_str() .ok_or_else(|| MyError::Conversion("Invalid UTF-8 path".to_string()))? .to_string(); let is_file = e.file_type().is_file(); Ok(MyStruct { path, is_file }) }) }) // 自动收集为Result<Vec<MyStruct>, MyError> .collect() } fn main() -> Result<(), Box<dyn Error>> { let items = walk_and_convert("./")?; for item in items { println!("{:?}", item); } Ok(()) }
关键细节说明
- 错误类型兼容:通过
From<WalkDirError> for MyError实现错误类型的自动转换,让WalkDir的遍历错误能无缝融入自定义错误体系。 - 迭代器链式处理:
map(|entry| entry.map_err(MyError::from)):将WalkDir返回的Result<DirEntry, WalkDirError>转为Result<DirEntry, MyError>。filter:保留符合业务条件的条目,若遇到错误条目则保留(最终会终止迭代并返回错误);如果需要跳过错误而非返回,可替换为filter_map(|entry| entry.ok().filter(|e| e.file_type().is_file()))。map(|entry| entry.and_then(...)):在每个成功的DirEntry上执行转换逻辑,同时处理转换过程中的异常(如路径非UTF-8)。collect():Rust的迭代器collect方法支持自动将Result<T, E>序列收集为Result<Vec<T>, E>——一旦遇到第一个错误就终止迭代并返回该错误,否则返回所有成功转换的结果。
内容的提问来源于stack exchange,提问作者SomeNameUser
相关产品推荐
相关产品推荐

