如何将迭代器收集为Result类型?Rust代码报错排查
问题
我写了一个筛选以_x开头文件的函数:
fn filter_files<P>(input_path: P) -> Result<Vec<DirEntry>, Box<dyn error::Error>> where P: AsRef<Path> { fs::read_dir(input_path)? .into_iter() .filter_map(|res| res.ok()) .filter(|dir_entry| dir_entry.file_name().to_str().unwrap().starts_with("_x")) .collect() }
运行时出现以下错误:
error[E0277]: a value of type `Result<Vec<DirEntry>, Box<dyn std::error::Error>>` cannot be built from an iterator over elements of type `DirEntry` --> src/main.rs:18:10 | 18 | .collect() | ^^^^^^^ value of type `Result<Vec<DirEntry>, Box<dyn std::error::Error>>` cannot be built from `std::iter::Iterator<Item=DirEntry>`
已知fs::read_dir(...)可能返回io::Error,所以必须返回Result类型,想知道正确的函数签名是什么,以及collect()的用法是否正确。
原因与解决办法
错误核心
你的函数返回Result<Vec<DirEntry>, ...>,但当前迭代器的元素是DirEntry(不是Result类型),collect()无法直接将普通迭代器收集为Result——只有当迭代器元素是Result时,collect()才能自动转换为包含集合的Result。
正确写法
有两种可行的调整方式:
方式一:保持原有返回签名,用Ok()包裹结果
迭代器最终产出的是DirEntry,直接把collect()得到的Vec<DirEntry>装进Ok即可:
use std::fs; use std::path::{Path, DirEntry}; use std::error::Error; fn filter_files<P>(input_path: P) -> Result<Vec<DirEntry>, Box<dyn Error>> where P: AsRef<Path> { Ok(fs::read_dir(input_path)? .into_iter() .filter_map(|res| res.ok()) // 忽略读取目录项的错误 .filter(|dir_entry| { // 替换unwrap,避免非UTF-8文件名导致panic dir_entry.file_name().to_str().map_or(false, |s| s.starts_with("_x")) }) .collect()) }
方式二:不忽略目录项读取错误(更严谨)
如果不想丢弃读取目录项时的错误,用map代替filter_map保留Result<DirEntry, io::Error>,此时迭代器元素是Result,collect()会自动转换为Result<Vec<DirEntry>, ...>:
use std::fs; use std::path::{Path, DirEntry}; use std::error::Error; fn filter_files<P>(input_path: P) -> Result<Vec<DirEntry>, Box<dyn Error>> where P: AsRef<Path> { fs::read_dir(input_path)? .into_iter() .map(|res| res) .filter(|res| { match res { Ok(dir_entry) => dir_entry.file_name().to_str().map_or(false, |s| s.starts_with("_x")), Err(_) => true, // 保留错误,最终会通过collect返回 } }) .collect() }
补充说明
原代码中dir_entry.file_name().to_str().unwrap()存在panic风险(文件名含非UTF-8字符时触发),建议用map_or做安全处理,如上述代码所示。
内容的提问来源于stack exchange,提问作者cogle
相关产品推荐
相关产品推荐

