【问题标题】:Exit with error code in go?退出时出现错误代码?
【发布时间】:2013-09-28 15:05:26
【问题描述】:

退出带有一些错误代码的程序的惯用方法是什么?

Exit 的文档说“程序立即终止;延迟函数不运行。”,log.Fatal 只是调用Exit。对于不是令人发指的错误,在不运行延迟函数的情况下终止程序似乎很极端。

我是否应该传递一些指示存在错误的状态,然后在我知道可以安全退出的某个时间点调用Exit(1),并且所有延迟函数都已运行?

【问题讨论】:

  • 如果全局变量状态默认为clean,在非致命错误时设置为dirty。在您的main() 退出之前,您可以检查该变量。不是很好,但在某些情况下它可能是最简单的解决方案。 (我很高兴 cmets 不能被投反对票 :))
  • 是的,这基本上就是我最终所做的。我觉得它不优雅,因为我必须避免延迟 main 中的任何内容(因为我仍然调用 Exit(1) 来设置返回码,并且不想杀死我的延迟 fn),所以我坚持了曾经是我的 main (这只有三行,其中之一是延迟)到一个函数中。我希望有人会有更好的方法。到目前为止,一个人回复了 os.Exit,然后当我评论我在帖子中引用 os.Exit 文档时删除了他们的回复,现在还有另一个答案指向我 os.Exit。

标签: error-handling go exit


【解决方案1】:

是的,实际上。 os 包提供了这个。

package main

import "os"

func main() {
    os.Exit(1)
}

http://golang.org/pkg/os/#Exit

编辑:所以看起来你知道 Exit。本文概述了 Panic,它将让延迟函数在返回之前运行。将它与出口结合使用可能是您正在寻找的。 http://blog.golang.org/defer-panic-and-recover

【讨论】:

  • 我很确定@dan 知道这件事。
  • 也许我看错了,或者他编辑了,但我以为他在说别的东西。
【解决方案2】:

正如 fas 所说,你有来自 os 包的func Exit(exitcode int)

但是,如果您需要应用延迟函数,您始终可以像这样使用defer 关键字:

http://play.golang.org/p/U-hAS88Ug4

您执行所有操作,影响一个错误变量,最后,当一切都清理干净后,您可以安全退出。

否则,您也可以使用 panic/recover: http://play.golang.org/p/903e76GnQ-

当您遇到错误时,您会感到恐慌,并在您捕获(恢复)它的地方结束清理。

【讨论】:

  • 我想我理解你在第一种方法中的意思,但这个例子让我有点困惑。为什么要推迟 fct1() 和 fct2()?这意味着它们将以相反的顺序执行!看来你打算something more like this,还是不打算?
【解决方案3】:

我在大多数真正的 main 包中都按照这些思路做一些事情,以便尽快采用 return err 约定,并有一个适当的终止:

func main() {
    if err := run(); err != nil {
        fmt.Fprintf(os.Stderr, "error: %v\n", err)
        os.Exit(1)
    }
}

func run() error {
    err := something()
    if err != nil {
        return err
    }
    // etc
}

【讨论】:

  • 测试此代码的最佳方法是什么?
  • 在功能测试中运行二进制文件。
  • _, _ = fmt.Fprintf(…) 明确忽略 Fprintf 返回的错误。
【解决方案4】:

在 python 中,我常用的模式转换为 go 如下所示:

func run() int {
    // here goes
    // the code

    return 1
}

func main() {
    os.Exit(run())
}

【讨论】:

  • 我认为这是最好的解决方案。您可以从run() 方法返回一个错误,并让main() 处理它,而不是它认为合适的方式。
【解决方案5】:

我认为最明确的方法是将exitCode 设置在main 的顶部,然后将defer 关闭作为下一步。这使您可以在main 中的任何位置更改exitCode,它的最后一个值将退出:

package main

import (
    "fmt"
    "os"
)

func main() {
    exitCode := 0
    defer func() { os.Exit(exitCode) }()

    // Do whatever, including deferring more functions

    defer func() {
        fmt.Printf("Do some cleanup\n")
    }()

    func() {
        fmt.Printf("Do some work\n")
    }()

    // But let's say something went wrong
    exitCode = 1

    // Do even more work/cleanup if you want

    // At the end, os.Exit will be called with the last value of exitCode
}

输出:

Do some work
Do some cleanup

Program exited: status 1.

去游乐场https://play.golang.org/p/AMUR4m_A9Dw

请注意,这样做的一个重要缺点是您不会在设置错误代码后立即退出进程。

【讨论】:

  • 暂且不论,但在编写了更多 Go 代码之后,我认为 stackoverflow.com/a/18969976/2958070(Gustavo Niemeyer 的回答)基本上在所有情况下都更清晰、更易于使用。跟踪函数调用比跟踪延迟要容易得多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
  • 2021-02-17
  • 2023-03-21
  • 1970-01-01
相关资源
最近更新 更多