Defer 不仅用于清理 - 好的还是坏的做法?

Defer used not only for cleanup - good or bad practice?

代码的延迟执行在 Go 中通常用于清理资源。它并不常见,但碰巧 defer 也用于执行常规业务逻辑。作为执行的最后一步,无论在哪个点函数命中return关键字。

Go Blog 页面上,我们可以发现“defer 语句将函数调用推送到列表中。保存的调用列表在周围函数 returns 之后执行。 Defer 通常用于简化执行各种清理操作的函数。"

他们确实提到了清理,但没有提到常规代码执行。显然,它可以执行任意代码,不一定要清理。这是最佳实践吗?社区是否就这方面的惯例或最佳实践达成一致?

Go 编译器不知道什么代码是清理代码。因此,如果它可以延迟清理代码,那么它显然也可以延迟任何非清理代码。

延迟函数有一些开销,显然必须管理调用堆栈,但如果它使您的代码更安全和/或更易于阅读,那就去做吧。使用它在 return 之前执行任何操作都非常好,甚至可以修改正在 returned 的值,甚至在恐慌的情况下。参见

有一件事你应该记住:延迟函数是 运行 即使代码崩溃(这对于清理代码是可取的),否则这将不是正常的执行流程。因此,与不使用 defer 相比,使用 defer 会有所不同。见相关:

让我们非常具体地说明 Go 延迟操作当前(Go 1.14 之前)添加的开销。

As of Go 1.13, most defer operations take about 35ns (reduced from about 50ns in Go 1.12). In contrast, a direct call takes about 6ns. This gap incentivizes engineers to eliminate defer operations from hot code paths, which takes away time from more productive tasks, leads to less maintainable code (e.g., if a panic is later introduced, the "optimization" is no longer correct), and discourages people from using a language feature when it would otherwise be an appropriate solution to a problem.

Proposal: Low-cost defers through inline code, and extra funcdata to manage the panic case