[Go] panic(nil) 会怎么样?

陪她去流浪 桃子 2019年04月09日 阅读次数:2567

在Go语言里面,经常会使用panic + recover的组合来模拟其它语言中的异常处理。像下面这样的写法:

package main

import (
	"fmt"
	"io"
)

func main() {
	defer func() {
		if exception := recover(); exception != nil {
			fmt.Println(exception)
		}
	}()
	panic(io.EOF)
}

上面的代码将会打印出:EOF

有一点值得思考的是,我们通过exception != nil的方式来判断是否发生了异常是否合理? 因为,实际上panic允许参数为nil的。如果为panic(nil),会发生什么?

答案是:recover成功捕获异常,但是我们却没有对它作任何处理。 因为:recover在返回nil的时候无法区别是没有抛出异常还是抛出了一个nil异常

recover官方说明文档如下(注意加粗的那句话):

The recover built-in function allows a program to manage behavior of a panicking goroutine. Executing a call to recover inside a deferred function (but not any function called by it) stops the panicking sequence by restoring normal execution and retrieves the error value passed to the call of panic. If recover is called outside the deferred function it will not stop a panicking sequence. In this case, or when the goroutine is not panicking, or if the argument supplied to panic was nil, recover returns nil. Thus the return value from recover reports whether the goroutine is panicking.

这样一来,语言是乎出现了歧义。

GitHub上也同样出现了这样的提议,建议区别对待这两种返回值,详见:proposal: promote panic(nil) to non-nil panic value

大家各抒己见,比如有人提议像下面这样:

if e, ok := recover(); ok {
    // do recovery stuff
}

也就是允许recover也可以像someMap[key]这样允许返回一个值或两个值。这样同样兼容以前的代码。是一个很不错的提议。但是,从回帖看,官方好像不是很喜欢这样做。不然早就已经提上日程了。

标签:Go