3 回答
TA贡献1829条经验 获得超9个赞
引用内置函数的文档recover():
如果在延迟函数之外调用恢复,它不会停止恐慌序列。
在您的第二种情况下,recover()它本身就是延迟函数,显然 recover()不会调用自己。所以这不会停止恐慌序列。
如果它自己recover()调用recover(),它会停止恐慌序列(但为什么会这样做?)。
另一个有趣的例子:
下面的代码也不会惊慌(在Go Playground上试试):
package main
func main() {
var recover = func() { recover() }
defer recover()
panic("panic")
}
这里发生的事情是我们创建了一个recover函数类型的变量,它具有调用内置函数的匿名函数的值recover()。并且我们指定调用recover变量的值作为延迟函数,因此recover()从中调用内置函数会停止恐慌序列。
TA贡献1862条经验 获得超7个赞
该处理恐慌部分提到,
两个内置函数
panic
和recover
,帮助报告和处理运行时恐慌该
recover
函数允许程序管理恐慌 goroutine 的行为。假设一个函数
G
延迟了一个D
调用的函数,recover
并且 apanic
出现在G
正在执行的同一个 goroutine 上的函数中。当延迟函数的运行达到 时
D
,D
的调用返回值recover
将是传递给恐慌调用的值。
如果 D 正常返回,没有开始新的恐慌,恐慌序列就会停止。
这说明这recover
意味着在延迟函数中调用,而不是直接调用。
当它恐慌时,“延迟函数”不能是内置函数recover()
,而是在defer 语句中指定的函数。
DeferStmt = "defer" Expression .
表达式必须是函数或方法调用;不能用括号括起来。
内置函数的调用与表达式语句一样受到限制。除了特定的内置函数,函数和方法调用和接收操作都可以出现在语句上下文中。
TA贡献2051条经验 获得超10个赞
一个观察是,这里真正的问题是设计,defer因此答案应该是这样的。
激发这个答案,defer目前需要从 lambda 中获取一级嵌套堆栈,并且运行时使用此约束的特定副作用来确定是否recover()返回 nil。
这是一个例子:
func b() {
defer func() { if recover() != nil { fmt.Printf("bad") } }()
}
func a() {
defer func() {
b()
if recover() != nil {
fmt.Printf("good")
}
}()
panic("error")
}
将recover()在b()应返回零。
在我看来,更好的选择是将defer函数 BODY 或块作用域(而不是函数调用)作为参数。在这一点上,panic和所述recover()返回值可以被绑定到特定堆栈帧,任何内堆栈帧将具有nilpancing上下文。因此,它看起来像这样:
func b() {
defer { if recover() != nil { fmt.Printf("bad") } }
}
func a() {
defer {
b()
if recover() != nil {
fmt.Printf("good")
}
}
panic("error")
}
在这一点上,很明显它a()处于恐慌状态,但b()不是,并且不需要任何副作用,例如“位于延迟 lambda 的第一个堆栈帧中”,以正确实现运行时。
因此,这里有悖常理:之所以没有按预期工作,是defer因为 go 语言中关键字的设计存在错误,这是使用不明显的实现细节副作用解决的,然后编码为这样的。
- 3 回答
- 0 关注
- 359 浏览
添加回答
举报