`panic`和`log.Fatalln()`在结果上有什么区别?

huangapple go评论84阅读模式
英文:

What are the differences in outcome for panic vs log.Fatalln()?

问题

根据log.Fatalln()的文档:

Fatalln函数等同于Println()后跟一个os.Exit(1)的调用。

Fatalln的源代码如下:

// Fatalln is equivalent to Println() followed by a call to os.Exit(1).
func Fatalln(v ...interface{}) {
    std.Output(2, fmt.Sprintln(v...))
    os.Exit(1)
}

看起来它们的主要区别在于错误是否可恢复(因为可以恢复panic),除此之外还有其他显著的区别吗?

panic的接口定义如下:

// The panic built-in function stops normal execution of the current
// goroutine. When a function F calls panic, normal execution of F stops
// immediately. Any functions whose execution was deferred by F are run in
// the usual way, and then F returns to its caller. To the caller G, the
// invocation of F then behaves like a call to panic, terminating G's
// execution and running any deferred functions. This continues until all
// functions in the executing goroutine have stopped, in reverse order. At
// that point, the program is terminated and the error condition is reported,
// including the value of the argument to panic. This termination sequence
// is called panicking and can be controlled by the built-in function
// recover.
func panic(v interface{})

看起来panic不返回任何内容。

这是它们的主要区别吗?否则,在应用程序中它们似乎执行相同的功能,假设panic没有被恢复。

英文:

From the documentation on log.Fatalln():

> func Fatalln(v ...interface{}) Fatalln is equivalent to Println()
> followed by a call to os.Exit(1).

The source code for Fatalln:

   310	// Fatalln is equivalent to Println() followed by a call to os.Exit(1).
   311	func Fatalln(v ...interface{}) {
   312		std.Output(2, fmt.Sprintln(v...))
   313		os.Exit(1)
   314	}

It seems the main difference is whether or not the error is recoverable (since you can recover a panic) - is there anything more significantly different between these?

Panic's interface definition is:

   215	// The panic built-in function stops normal execution of the current
   216	// goroutine. When a function F calls panic, normal execution of F stops
   217	// immediately. Any functions whose execution was deferred by F are run in
   218	// the usual way, and then F returns to its caller. To the caller G, the
   219	// invocation of F then behaves like a call to panic, terminating G's
   220	// execution and running any deferred functions. This continues until all
   221	// functions in the executing goroutine have stopped, in reverse order. At
   222	// that point, the program is terminated and the error condition is reported,
   223	// including the value of the argument to panic. This termination sequence
   224	// is called panicking and can be controlled by the built-in function
   225	// recover.
   226	func panic(v interface{})

It appears panic does not return anything.

Is that the primary difference? Otherwise, they seem to perform the same function in an application, assuming the panic is not recovered.

答案1

得分: 112

日志消息会发送到配置的日志输出,而 panic 只会写入 stderr。

panic 会打印堆栈跟踪,这可能与错误无关。

延迟函数在程序发生 panic 时会执行,但调用 os.Exit 会立即退出,并且延迟函数无法运行。

通常,只在编程错误时使用 panic,其中堆栈跟踪对错误的上下文很重要。如果消息不是针对程序员的,那么你只是将消息隐藏在多余的数据中。

英文:
  • The log message goes to the configured log output, while panic is only going to write to stderr.

  • Panic will print a stack trace, which may not be relevant to the error at all.

  • Defers will be executed when a program panics, but calling os.Exit exits immediately, and deferred functions can't be run.

In general, only use panic for programming errors, where the stack trace is important to the context of the error. If the message isn't targeted at the programmer, you're simply hiding the message in superfluous data.

答案2

得分: 10

panic在小程序中经常被用来在出现错误时终止程序,这些错误可能是你不知道如何处理或者不想处理的。panic的缺点就是它会终止程序(除非你使用recover)。一般来说,除非你打算从panic中恢复,或者发生了一些你无法从中恢复或无法优雅地终止程序的情况,否则不应该使用panic。例如,考虑一个提供功能的API,但这个API在某个地方暗中使用了panic,你注意到你的程序在生产环境中因此终止了。因此,你编写的任何代码的"外部API"都应该从panic中恢复,并返回一个错误。同样的情况也适用于任何终止程序的情况。

然而,os.Exit()无法从中恢复,也不会执行延迟操作。

英文:

panic is often used in little programs to just terminate the program once an error appears you don't know how to handle or don't want to handle. The downside of panic is exactly that: it'll terminate the program (mostly, unless you use recover). It's generally not good to use panic unless you intend to recover from it or unless something has happened you really can't recover from at all nor where you can gracefully terminate the program otherwise. Consider for example an API that offers you functionality but that API secretly has a panic somewhere and you notice that your program terminates in production due to this. Thus, the "outward API" of whatever code you write should recover from panics and return an error instead. The same thing applies to anything that terminates the program.

However, os.Exit() can't be recovered from nor does it execute defers.

答案3

得分: 1

另一个关于 panic 和 log.Fatalln 的观察:

如果一个应该返回值的函数没有无条件的 return 语句,会出现编译时错误(missing return)。现在,如果该函数调用了 panic,它会编译通过,但如果调用了 log.Fatalln,则不会通过编译:

// 即使调用了 log.Fatalln,这段代码也不会编译通过("missing return"):
func my_func(key string) string {
	my_map := map[string]string{"key": "value"}
	if val, key_exists := my_map[key]; key_exists {
		return val
	}
	log.Fatalln(fmt.Sprintf("unknown key %q", key))
}
// 如果调用了 panic,这段代码会编译通过:
func my_func(key string) string {
	my_map := map[string]string{"key": "value"}
	if val, key_exists := my_map[key]; key_exists {
		return val
	}
	panic(fmt.Sprintf("unknown key %q", key))
}
英文:

Another observation about panic vs log.Fatalln:

If a function supposed to return something does not have an unconditional return statement, there is a compile-time error (missing return). Now, if that function calls panic it will compile just fine, but not if it calls log.Fatalln:

// this will not compile ("missing return") even if it calls log.Fatalln:
func my_func(key string) string {
	my_map := map[string]string{"key": "value"}
	if val, key_exists := my_map[key]; key_exists {
		return val
	}
	log.Fatalln(fmt.Sprintf("unknown key %q", key))
}
// this will compile just fine if it calls panic:
func my_func(key string) string {
	my_map := map[string]string{"key": "value"}
	if val, key_exists := my_map[key]; key_exists {
		return val
	}
	panic(fmt.Sprintf("unknown key %q", key))
}

huangapple
  • 本文由 发表于 2016年3月15日 04:02:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/35996966.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定