如何扁平化Rust代码中的嵌套if let与if语句?
问题描述
我正在对字符串进行「归一化(normalizing)」处理,随后用它来搜索文件名的归一化版本:
use glob::glob; fn main() { let text = "Hello:world- This is a test string._,\""; let normalized = normalize(text); let pattern = "/home/alex/Downloads/papers/*"; for entry in glob(pattern).expect("Failed to read glob pattern") { if let Ok(path) = entry { if let Some(file_name) = path.file_name().and_then(|name| name.to_str()) { let file_name_normalized = normalize(file_name); if file_name_normalized.contains(&normalized) { println!("{:?}", path); } } } } } fn normalize(text: &str) -> String { let normalized = text .replace(&[':', ':', '-', '—', '_', ',', '.', '"'][..], "") .to_lowercase() .split_whitespace() .collect::<Vec<&str>>() .join(" "); normalized }
输出结果:
"/home/alex/Downloads/papers/Hello:world- This is a test string._,".pdf"
该代码可正常运行,但我想知道是否可以将所有嵌套的if let语句和if语句进行扁平化处理?
解决方案
可以利用Rust的迭代器适配器和?运算符,将嵌套的判断逻辑扁平化,让代码更简洁线性。优化后的代码如下:
use glob::glob; fn main() { let text = "Hello:world- This is a test string._,\""; let normalized = normalize(text); let pattern = "/home/alex/Downloads/papers/*"; glob(pattern) .expect("Failed to read glob pattern") .filter_map(|entry| entry.ok()) .filter_map(|path| path.file_name()?.to_str().map(|name| (path, name))) .filter(|(_, file_name)| normalize(file_name).contains(&normalized)) .for_each(|(path, _)| println!("{:?}", path)); } fn normalize(text: &str) -> String { text.replace(&[':', ':', '-', '—', '_', ',', '.', '"'][..], "") .to_lowercase() .split_whitespace() .collect::<Vec<&str>>() .join(" ") }
优化说明:
filter_map(|entry| entry.ok()):替代外层if let Ok(path) = entry,直接过滤掉glob返回的错误条目,只保留成功的路径。filter_map处理文件名提取:把path.file_name().and_then(|name| name.to_str())的逻辑整合到filter_map中,用?处理Option链式调用,失败则跳过当前条目;同时通过map绑定路径与文件名,方便后续使用。filter判断匹配条件:将最后一层if判断转为filter适配器,只保留符合匹配规则的条目。for_each执行打印:替代原循环体的打印逻辑,让整个流程通过迭代器链式调用完成,完全消除嵌套结构。
这种写法保持了可读性,同时符合Rust的惯用风格,把分支逻辑转化为线性的迭代器操作。
内容的提问来源于stack exchange,提问作者wyc
相关产品推荐
相关产品推荐

