`..._or()` 与 `..._or_else(|| {})` 的适用场景对比及优势解析
..._or() 与 ..._or_else(|| {}) 的适用场景对比及优势解析
咱们先把这两个方法的核心区别掰扯明白,再聊..._or()的优势和Clippy那条规则的道理~
首先回忆一下两者的求值逻辑:
..._or_else()是惰性求值:只有当原变量是Option::None(或者Result::Err)的时候,才会执行传入的闭包来计算默认值。比如你给的例子:
只有let value = option.unwrap_or_else(|| compute_value(argument));option是None时,compute_value(argument)才会被调用,非常节省资源。..._or()是立即求值:不管原变量是Some还是None,你传入的默认值表达式会先被计算出来,之后再判断要不要用这个值。
那回到你的问题:..._or()到底有没有优势?答案是肯定的,主要体现在这几个场景:
1. 代码简洁性(最核心的优势)
当你的默认值是预先计算好的变量、常量,或者是无开销的简单表达式时,..._or()的写法比..._or_else()简洁太多了。
比如:
- 用
or():let value = option.or(Some(42)) - 用
or_else():let value = option.or_else(|| Some(42))
显然前者更直观,没必要多套一层闭包。这也是Clippy会建议你把_or_else()改成_or()的原因——这种场景下惰性求值完全是多余的,反而增加了语法冗余,_or()的写法更简单直接。
2. 极端场景下的微小性能优势
虽然日常开发里几乎感知不到,但如果闭包本身有一点点额外开销(比如闭包的捕获逻辑、栈帧创建),而默认值是现成的,用..._or()可以避免这部分微小的开销。不过这个优势非常次要,大部分时候我们优先考虑代码可读性。
但要注意!不是所有场景都能随便替换
有两种情况绝对不能把_or_else()改成_or():
- 默认值计算有副作用:比如计算默认值的操作会修改全局变量、发起网络请求、读写文件,或者调用有副作用的函数。
_or()会立即执行这些操作,不管原变量是不是None/Err,这会彻底改变程序的语义。 - 默认值计算开销很大:比如需要遍历一个大集合、进行复杂的运算,用
_or()会导致这些运算白做(如果原变量是Some/Ok的话),浪费资源。
另外你提到的Deref/Index的情况也要注意:如果默认值是通过Deref或Index获取的(比如&my_vec[0]),而这些操作被实现成有副作用的(虽然不推荐这么做),_or()的立即求值会提前触发副作用,导致程序行为不符合预期,这种情况也不推荐用_or()。
总结一下适用场景
- 用
..._or():默认值是常量、预先计算好的变量,或者无副作用、无开销的简单表达式,追求代码简洁直观。 - 用
..._or_else():默认值计算有副作用、开销大,或者需要延迟计算直到真正需要的时候。
备注:内容来源于stack exchange,提问作者Alexdelia
相关产品推荐
相关产品推荐

