Rust中如何重复调用函数至返回Some并避免使用.unwrap()?
编译器词法分析中unwrap的使用与优化实现
生产环境里的常见情况
你这种“理论上不会出现None所以用unwrap”的写法,在生产环境里偶尔能看到,但大部分成熟项目会换成expect()——哪怕逻辑上绝对不会触发panic,也会加个明确的错误提示,比如expect("Failed to get token after skipping whitespace")。真要是哪天get_longest_match出了逻辑bug(比如EOF处理漏了),有错误信息能立刻定位问题,比裸unwrap直接崩溃强得多。
更符合Rust风格的实现方式
1. 用loop直接返回有效token
最简洁直观的写法就是把循环和取值合并,完全不用unwrap:
pub fn next_token(&mut self) -> Token { loop { if let Some(token) = self.get_longest_match() { return token; } } }
这个逻辑很直白:一直调用get_longest_match,拿到非None的token就直接返回,省掉中间变量,也彻底避免了unwrap的风险。
2. 封装成Iterator(更贴合Rust惯用风格)
如果把你的词法分析器实现成Iterator,代码会更规整,后续批量处理token也更方便:
impl Iterator for Lexer { type Item = Token; fn next(&mut self) -> Option<Self::Item> { loop { match self.get_longest_match() { Some(token @ Token::Eof) => return Some(token), Some(token) => return Some(token), None => continue, } } } } // 基于迭代器实现next_token: pub fn next_token(&mut self) -> Token { self.next().expect("Unexpected end of input without EOF token") }
这里用expect()替代unwrap,保留了错误提示,同时利用迭代器的语义让代码更符合Rust的设计思路。
3. 绕开unwrap的另类写法(不推荐)
还有一种写法能避免unwrap,但可读性极差,几乎没人用:
pub fn next_token(&mut self) -> Token { let mut token = Token::default(); // 需Token实现Default trait while let None = self.get_longest_match().map(|t| token = t) { // 空循环体 } token }
这种写法依赖Token的默认值,逻辑晦涩,远不如第一种loop写法清晰。
总结
- 生产环境尽量别用裸unwrap,换成带错误信息的expect,调试时能快速定位问题。
- 首推
loop + if let的写法,简洁、安全,逻辑一目了然。
内容的提问来源于stack exchange,提问作者Alex Bieg
相关产品推荐
相关产品推荐

