Rust两段等价函数match模式匹配一编译一报错,咨询是否非穷尽
Rust match模式非穷尽编译错误问题
我编写了两段逻辑等价的Rust函数,其中一段可正常编译,另一段无法编译。
可编译的程序1
pub fn majority_element<T: Eq>(nums: &[T]) -> Option<&T> { nums.iter().fold(None, |acc, curr| { match acc { None => Some((1, curr)), Some((0, prev)) if prev != curr => Some((1, curr)), Some((count, prev)) => Some((count + if prev == curr { 1 } else { -1 }, prev)), } }).map(|(_, val)| val) }
无法编译的程序2
pub fn majority_element<T: Eq>(nums: &[T]) -> Option<&T> { nums.iter().fold(None, |acc, curr| { match acc { None => Some((1, curr)), Some((0, prev)) if prev != curr => Some((1, curr)), Some((count, prev)) if prev == curr => Some((count + 1, prev)), Some((count, prev)) if prev != curr => Some((count - 1, prev)), } }).map(|(_, val)| val) }
报错信息
error[E0004]: non-exhaustive patterns: `Some(_)` not covered --> src/lib.rs:3:15 | 3 | match acc { | ^^^ pattern `Some(_)` not covered |
我更倾向于第二段代码,因其能更清晰表达意图。请问这是编译器问题,还是我的模式确实非穷尽?若为后者,我遗漏了什么?注:acc的类型为Option<(usize, &T)>
解答
这不是编译器的问题,你的模式确实属于非穷尽匹配。
Rust的match穷尽性检查不会分析守卫条件(if子句)的逻辑完备性,它仅基于模式本身的结构进行判断:
- 程序2的match分支中,前两个分支分别匹配
None和Some((0, prev))(带守卫),后两个分支都是Some((count, prev))(带不同守卫)。 - 编译器无法推导这两个带守卫的分支能覆盖所有
Some((count, prev))的情况(即便逻辑上prev == curr和prev != curr是互斥且完备的),因此会判定存在未覆盖的Some(_)模式。
而程序1的第三个分支是不带守卫的Some((count, prev)),直接覆盖了所有未被前两个分支匹配的Some情况,所以编译器认为匹配是穷尽的。
修改方案
要保留程序2的清晰逻辑同时通过编译,可将最后一个分支的守卫条件去掉,作为兜底分支:
pub fn majority_element<T: Eq>(nums: &[T]) -> Option<&T> { nums.iter().fold(None, |acc, curr| { match acc { None => Some((1, curr)), Some((0, prev)) if prev != curr => Some((1, curr)), Some((count, prev)) if prev == curr => Some((count + 1, prev)), Some((count, prev)) => Some((count - 1, prev)), // 去掉守卫,作为兜底 } }).map(|(_, val)| val) }
逻辑上该兜底分支只会进入prev != curr的场景,与你原本的意图完全一致,同时能被编译器识别为穷尽匹配。
内容的提问来源于stack exchange,提问作者user19055902
相关产品推荐
相关产品推荐

