Kotlin代码审查:7个会毁掉你项目的陷阱

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么Kotlin代码审查不是关于“我会用不同的方式写”?

\n\n

Code review(或代码审查)是任何值得尊敬的团队中的神圣仪式。但当谈到Kotlin时,许多开发者会陷入困惑。“这里的一切都如此简洁!”,“嗯,这是一种基于表达式的语言”——您一边滚动拉取请求一边想。但您错了。

\n\n

Kotlin很漂亮,但也暗藏玄机。它为您提供了强大的工具:作用域函数、密封类、协程。同时,也提供了同样多的机会让您搬起石头砸自己的脚。在本文中,我们将分析在Kotlin代码审查中真正需要注意什么,以确保您的代码不会变成带有可空副作用的“意大利面条式怪物”。

\n\n

本文不是语法教程。这是一份供审查者使用的实用检查清单,他们希望看到的不仅仅是能工作的代码,而是可维护且安全的产品。

\n\n

1. 空安全:当“?”不是万能药时

\n\n

Kotlin以其空安全为傲。这是正确的。但在代码审查中,您必须检查的不仅仅是“!!”的存在,而是与可空类型相关的逻辑。

\n\n

什么绝对应该引起警惕?

\n\n
    \n
  • 无节制地使用“!!”。如果开发者使用了!!,他们应该在注释中解释为什么这个值保证不为null。如果没有解释,那就是一个bug。
  • \n
  • 安全调用(?.)和Elvis操作符(?:)的链式使用。它们常常掩盖逻辑错误。例如:
  • \n
\n\n
// 问题:如果 user?.address?.city == null,\n// 我们会默默地返回“Unknown”而不记录日志\nval city = user?.address?.city ?: "Unknown"\n
\n\n

应该怎么做? 如果null是异常情况,请使用requireNotNull或checkNotNull。如果这是正常行为,请记录日志。

\n\n
val city = user?.address?.city\n    ?: run {\n        logger.warn("User $userId has no city")\n        "Unknown"\n    }\n
\n\n

在kotlin代码审查中,始终要问:“如果这个null是一个我们现在忽略了的bug,该怎么办?”

\n\n

2. 作用域函数:明智地使用let、apply、run

\n\n

作用域函数是Kotlin的强大之处。但在实践中,我看到它们被当作锤子来敲任何钉子。Kotlin代码检查应该包括分析:“为什么这里用let而不是run?”

\n\n

典型的陷阱:

\n\n
    \n
  • 使用let进行非空检查。可以,但不要将它们嵌套在一起:
  • \n
\n\n
// 糟糕\nuser?.let { u ->\n    address?.let { a ->\n        process(u, a)\n    }\n}\n\n// 良好\nif (user != null && address != null) {\n    process(user, address)\n}\n
\n\n
    \n
  • 使用apply进行对象修改。这是它的天然用途。但如果您在let内部使用apply——打住。这闻起来像意大利面条式代码。
  • \n
\n\n

请记住:with用于分组调用,also用于副作用(日志记录),run用于在上下文中进行计算。不要混淆。

\n\n

3. 不可变性:var是危险信号

\n\n

Kotlin提倡使用val。这很好。但在Kotlin代码审查中,我经常看到开发者在可以使用val加复制的地方写var。

\n\n
// 不好\nvar result = mutableListOf<Int>()\nitems.forEach { result.add(it * 2) }\n\n// 良好\nval result = items.map { it * 2 }\n
\n\n

规则很简单:如果您看到var,就问:“为什么不用val?”大多数情况下,答案会让您惊讶:“我没想过。”

\n\n

唯一的例外是当确实需要修改时(例如,在累加循环中)。但即使在那里,也常常可以用fold或reduce替换。

\n\n

4. 密封类和when:不要忘记else

\n\n

密封类是优雅的替代

博客

书籍推荐