【问题标题】:shouldn't unreachable code after os.Exit be flaggedos.Exit 后不应该无法访问代码
【发布时间】:2019-05-29 19:38:54
【问题描述】:

转到 1.12 窗口

在 os.Exit 之后而不是之前放错了 fmt.Println, 这不应该导致编译器失败或至少警告吗?

package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Hello, playground")
    os.Exit(0)
    fmt.Println("Good By, playground")
}

【问题讨论】:

  • 它可能会被 linter 捕获,但编译器并不关心语义。您有 3 个函数调用,这是合法的。你不能有一个return 后跟更多代码,但对于编译器来说os.Exit 只是另一个函数。
  • @Adrian 实际上在 Go 中,return 之后有代码并不是错误。
  • @icza 对不起,你是对的,我忘了 Playground 在 go run 之前运行 go vet

标签: go


【解决方案1】:

os.Exit() 就像任何其他函数一样,编译器不应该知道它会终止应用程序,因此后面的其余代码是无法访问的。 os.Exit() 只是一个示例,还有更多示例,例如log.Fatal()(调用os.Exit())。更不用说您还可以创建一个调用其中之一的函数,编译器应该多远才能检测到所有或大部分?

更进一步,Go 编译器不会检测也不会标记“真正”无法访问的代码。使用return 语句时的以下变化对编译器来说甚至是显而易见的:

func main() {
    fmt.Println("Hello, playground")
    return
    fmt.Println("Good By, playground")
}

然而它编译和运行都很好,并且输出(在Go Playground上试试):

Hello, playground

因此编译器不会检测到无法访问的代码,但 go vet 会检测到,这也是由 Go Playground 运行的,因此您可以看到应用程序的输出前缀为:

./prog.go:10:2: unreachable code
Go vet exited.

这已经被提过,见cmd/gc: report unreachable code #9501。罗伯特·格里斯默的回答是:

一般来说,Go 的理念不是不惜一切代价保护程序员免受错误的影响。故意不为无法访问的代码引发错误。这也不是一种很常见的错误。此外,为调试引入早期返回通常很有用,这可能会导致大量无法访问的代码。目前尚不清楚利大于弊。

未使用的变量与 Go 在短变量声明中的重新声明机制相结合可能导致细微的查找错误 - 因此未使用变量的错误消息。这是一种从经验中演变而来的机制,是针对具体问题的务实解决方案。

报告未使用的导入是因为它有助于控制依赖关系 - 这是大型系统设计中的一个重要工具,并且作为副作用它还可以保持编译时间很快。又是一个非常深思熟虑的设计决定。

最后,使死代码成为错误将是一项重大的语言更改,目前这是不可能的。

使用 go vet。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多