保持if语句无副作用

Lobsters Hottest 新闻

摘要

文章建议保持if语句无副作用以提高代码可读性,通过示例说明常见陷阱和更清晰的替代方案。

<p><a href="https://lobste.rs/s/buroqq/keep_if_clauses_side_effect_free">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/09/26 05:21

# 保持if子句无副作用 来源:https://www.teamten.com/lawrence/programming/keep-if-clauses-side-effect-free.html 避免编写带有副作用的`if`子句: ```` if (enqueueMessage(message)) { ... } ```` `if`语句的唯一功能是测试条件是否为真,而非作为测试的副作用来执行代码。直接使用返回值(如上例)的一个问题是返回值的*含义*不明确:`enqueueMessage()`返回true是表示消息已入队,还是表示队列已满?请通过变量使其显式化: ```` boolean success = enqueueMessage(message); if (success) { ... } ```` 以上代码更符合自然语言表达:"如果操作成功,..."。无副作用的方法(我们希望)能通过返回值清晰表达意图,例如`isEmpty()`。这种情况不仅限于布尔值方法。以下代码不够清晰: ```` if (flushQueue() == 0) { ... } ```` 而改写为: ```` int itemsFlushed = flushQueue(); if (itemsFlushed == 0) { ... } ```` 在`if`语句中调用有副作用方法的另一个缺点是:快速浏览代码的读者可能完全忽略该调用。对比上述两个`flushQueue()`示例:第一个可能被误认为是查询队列属性的函数;第二个则清晰分为两部分——先执行操作,再进行测试。考虑我在线上环境中见过的这段代码: ```` if (!categorySeen.add(categoryID)) continue; ```` 我最初无法理解循环体中向集合添加元素的逻辑。由于预期`if`语句内容不应产生副作用,我将这行代码误读为: ```` if (!categorySeen.contains(categoryID)) continue; ```` 即使注意到`add()`方法,我也未能理解其功能——您能理解吗?(根据`Set`的Java文档,`add()`方法在集合未包含指定元素时返回`true`)。注意其中因`continue`导致的复杂逻辑(参见避免使用continue:https://www.teamten.com/lawrence/programming/avoid-continue.html):只有当`categoryID`*并非*已见过时才会执行后续代码——这里包含三重否定:`continue`的否定、`!`运算符的否定,以及API描述中的"不包含"含义。多么混乱!不如这样改写: ```` boolean isNewCategory = categorySeen.add(categoryID); if (isNewCategory) { ... } ```` 以下是副作用方法与短路求值滥用的危险组合: ```` if (queueNeedsFlushing() && flushQueue() == 0) { ... } ```` 第二个调用极易被忽略。短路求值本应用于保护无副作用语句的求值错误,例如: ```` if (count > 0 && total/count >= MIN_AVERAGE) { ... } ```` 或: ```` if (name != null && name.endsWith(".png")) { ... } ```` 切勿利用此机制规避有副作用的方法调用。这正是`if`语句的诞生初衷: ```` if (queueNeedsFlushing()) { int itemsFlushed = flushQueue(); if (itemsFlushed == 0) { ... } } ```` 若认为简洁版本优于上述三行代码,实则是对你自身和未来读者的损害。当后续因频繁遗漏重要方法调用而导致代码追踪困难时,多写两行代码是微不足道的代价。 ~ 查看所有编程文章 ~ (https://www.teamten.com/lawrence/programming/)

相似文章

捕获子句作为效果

Lobsters Hottest

本文探讨了Rust中显式捕获子句作为move表达式的替代方案,提出了一种将引用转换为所有权值的一等语言特性,并分析了多种闭包捕获模式。

像人类会维护它一样编写代码

Hacker News Top

文章警告说,依赖LLM编写代码而不保持良好模式,会教会AI不良习惯,导致代码库充满重复逻辑,代码质量不断恶化。

Prolog编程的陷阱

Hacker News Top

关于Prolog编程中常见陷阱的指南,强调使用纯声明式构造而非不纯的构造,如cut、全局状态和低级I/O。