永远不要使用 ELSE 语句,编写更好的代码并成为更好的程序员

2025-06-04

永远不要使用 ELSE 语句,编写更好的代码并成为更好的程序员

过去几年我一直是一名专业程序员。在此期间,我的晋升非常迅速。我最初是一名实习生,但现在我已经是首席工程师,负责一套服务于140多个国家超过16万用户的产品。

最近,我回顾了这些年来我编写的所有代码(我仍然可以访问)。我用各种各样的语言编写过生产代码,包括 Haskell、Scala、Go、Python、Java 和 JavaScript。在所有这些代码中,我注意到一个明显的趋势:我几乎从不使用 ELSE 语句。

不过,我意识到我厌恶 else 语句背后有一个明确的理由。我认为它们不应该被使用,而应该被视为一种代码异味。我这样认为有两个原因:else 语句违反了视线规则,而且它们总是缺乏上下文。在展示如何避免使用 else 语句之前,我会详细解释这两点。

视线规则#

我坚信,代码应该优化以便未来人类阅读,而不是优化以便机器执行。在这一点上,我赞同 Donald Knuth 的观点:

“程序是供人类阅读的,只是偶尔供计算机执行。”——唐纳德·克努斯,《计算机编程艺术》。

问题在于,代码的可读性是主观的:很难准确定义什么才能使代码可读。不过,有一条规则可以澄清这一点,那就是视线规则。这是 Go 社区中一条流行的规则。Mat Ryer在他的演讲和文章中对其进行了简明的定义。简而言之,就是代码中的“快乐路径”应该尽可能少地缩进。

快乐之路

相反,任何错误处理或特殊情况的代码都应该进一步缩进。

特例

任何遵循此规则的代码都具有一个独特的属性:只需扫描缩进最少的代码即可了解任何代码的功能。扫描缩进较多的代码则能显示所有可能发生的特殊情况和错误。这使得代码一目了然,非常容易理解。

那么 else 语句与此有何关系?

Else 语句存在问题,因为它们会强制代码缩进一层。这会让人突然搞不清楚哪些代码与“快乐路径”相关,以及哪些是特殊情况。

不清楚

这种缺乏清晰度的情况使得代码更难扫描,并损害了可读性。

缺乏上下文

快速高效地扫描代码的能力至关重要。独立地理解小段代码是其中的关键。我们不想为了理解代码库的一小部分而总是阅读每一行代码。

Else 语句使这一点更加困难,因为它们将条件和受其影响的代码分隔开来if。最好通过两个示例来解释。首先,你能说出运行这三行代码时会发生什么吗?



if myVariable == nil { 
    return “”
}


Enter fullscreen mode Exit fullscreen mode

希望以上解释足够清晰。不过,我们来看一个对比的例子:



} else { 
    return “”
}


Enter fullscreen mode Exit fullscreen mode

我们可以看到,如果没有这个if语句,我们就无法确定它到底想做什么。为什么它会返回一个空字符串?这是错误,还是“正常”行为?这段代码依赖于我们记住并阅读之前的上下文。当语句很短时,这无关紧要,但如果代码块中逻辑复杂if { … },或者我们快速浏览,那么将上下文与代码分离会严重损害可读性。当 if/else 语句嵌套,或者一个函数中有多个 if/else 语句时,这种情况会更加严重(这个 else 语句是针对哪个 if 语句的?)。

如何删除 else 语句?#

现在我们已经同意 else 语句很垃圾了。但这本身并没有多大帮助。真正的技巧在于如何避免它们。值得庆幸的是,有两种简单的方法可以做到这一点:

  • 反转if条件并提前返回,并且,
  • 创建辅助函数。

反转条件

这是我遇到的最常见的情况。它也有两种形式——一种else是隐式的,一种是显式的。显式版本如下所示:



func doSomething() error {
  if something.OK() {
    err := something.Do()
    if err != nil {
      return err
    }
  } else {
    return nil, errors.New("something isn't ok")
  }
}


Enter fullscreen mode Exit fullscreen mode

隐式函数类似,但本身不包含else任何语句。相反,它else只是通过简单地删除函数末尾来隐式地表示(这种隐式函数在 Python 或 JavaScript 中更常见,如果没有明确声明,则返回None或)。undefined



function doSomething() {
  if (something.OK()) {
    return something.Do()
  }
}


Enter fullscreen mode Exit fullscreen mode

再次强调,这并不能完全清晰地展现该行为的全部内容。如果不阅读整个函数,返回值就无法清晰。

通过简单地反转if条件,我们就可以解决所有这些问题。



function doSomething() {
  if (!something.OK()) {
    // return or throw error
  }
  return something.Do()
}


Enter fullscreen mode Exit fullscreen mode

现在我们可以扫描这个函数,清楚地看到缩进的错误条件和正常流程,满足视线规则。行为完全明确,并且没有上下文分离。这好多了。

辅助函数

我们也遇到了一些不直接导致 的 else 语句return。这通常是由于一些未正确隔离的特殊情况逻辑造成的。例如



  let charities
  if (country != "") {
    if (tier != "") {
      charities = getCharitiesByCampaignCountryAndTier(campaign, country, tier)
    } else {
      charities = getCharitiesByCampaignAndCountry(campaign, country)
    }
  } else {
    charities = getCharitiesByCampaign(campaign)
  }

  // do something with charities


Enter fullscreen mode Exit fullscreen mode

通过将慈善募捐逻辑合并到单独的函数中,可以提高代码的可读性。这样可以适当处理特殊情况,并提前返回。通过反转一些 if 语句,可以进一步改进代码的可读性。

例如:



function getCharities(campaign, country, tier) {
  if (country == "") {
    return getCharitiesByCampaign(campaign)
  }

  if (tier == "") {
    return getCharitiesByCampaignAndCountry(campaign, country)
  }

  return getCharitiesByCampaignCountryAndTier(campaign, country, tier)
}


Enter fullscreen mode Exit fullscreen mode

这个辅助函数巧妙地封装了我们需要的所有逻辑,消除了对任何 else 语句的需求,并且更好地将快乐路径代码保持在左侧。这使得代码更容易浏览,并且可读性也更高。

结论

Else 语句是一种奇怪的代码异味。它们强制错误处理和快乐路径的缩进级别相同,从而损害了所有代码的可读性。它们还具有将代码与影响代码的逻辑分离的独特能力。通过提前返回和将逻辑拆分为辅助函数这两种技巧,可以轻松避免使用 Else 语句。因此,它们是不必要的。通过避免使用 Else 语句,您可以编写更好的代码,并成为一名更优秀的程序员。

一些警告(以阻止学究们)。

  • 在 SQL 中,CASE WHEN ... ELSE ... 实际上是无法避免的。
  • 在 Scala 中,隐式返回(避免使用返回语句来实现引用透明性)意味着您必须使用它们 - 您实际上没有“提前返回”的能力。
  • 三元运算符很好。
  • 在python中,三元运算符使用else。这也很好。
文章来源:https://dev.to/dglsparsons/write-better-code-and-be-a-better-programmer-by-never-using-else-statements-4dbl
PREV
Flexbox 及其属性 - 解释
NEXT
招聘优秀开发人员时我们需要具备的三种特殊素质