从一个包中恢复和处理恐慌

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

panic and recover from a package

问题

我正在尝试弄清楚panic()recover()的工作原理。

#log包

package log

import (
	"fmt"
)

func Recover() {
	fmt.Println("正在恢复!")
	if err := recover(); err != nil {
		fmt.Println("错误消息已恢复!")
	}
}

#main包

package main

import (
	"fmt"
	log "www/pkg/log"
)

func main() {
	defer func() {
		log.Recover()
	}()
	
	panic("假错误!")
}

#输出

正在恢复!
panic: 假错误!

为什么错误消息已恢复!从未打印出来?

英文:

I'm trying to figure out how panic() and recover() works..

#log package

package log

import (
	"fmt"
)

func Recover() {
	fmt.Println("Recovering!")
	if err := recover(); err != nil {
		fmt.Println("Error message recovered!")
	}
}

#main package

package main

import (
	"fmt"
	log "www/pkg/log"
)

func main() {
	defer func() {
		log.Recover()
	}()
	
	panic("Fake error!")
}

#output

Recovering!
panic: Fake error!

Why is Error message recovered! never printed?

答案1

得分: 2

应用程序必须直接从延迟函数中调用recover来处理panic。

规范中提到了延迟函数调用recover的情况:

假设函数G延迟调用了函数D,而函数D又调用了recover,并且在执行G的goroutine中的某个函数中发生了panic。当延迟函数的运行达到D时,D调用recover的返回值将是panic调用时传递的值。

这是一个微妙的问题,它不允许对recover进行间接调用。此外,关于recover的返回值的部分提到了从延迟函数中直接调用:

如果满足以下任一条件,则recover的返回值为nil:

  • recover不是由延迟函数直接调用的。

最近我遇到了这个问题。由于规范非常简洁,有时需要仔细阅读才能理解其中的一些要点。

英文:

The application must call recover directly from the deferred function to handle the panic.

The specification talks about the deferred function calling recover:

> Suppose a function G defers a function D that calls recover and a panic occurs in a function on the same goroutine in which G is executing. When the running of deferred functions reaches D, the return value of D's call to recover will be the value passed to the call of panic.

It's subtle, but it does not allow for an indirect call to recover. Also, the passage on the return value from recover mentions a direct call from the deferred function:

> The return value of recover is nil if any of the following conditions holds:
>
> - recover was not called directly by a deferred function.

I was caught by this issue recently. Because the specification is very concise, it sometimes takes careful reading to pick up some points.

答案2

得分: 1

recover只针对当前的goroutine执行:文档中说:

在延迟函数中执行recover的调用(但不包括由其调用的任何函数)会通过恢复正常执行来停止panic序列

当你调用另一个函数时,它没有发生panic,因此在其中间调用recover会返回nil,你无法捕获到panic。

英文:

revocer only refers to the execution of the current goroutine: The docs say:

Executing a call to recover inside a deferred function **(but not any function called by it)** stops the panicking sequence by restoring normal execution

When you called another function, it did not panic, hence calling recover in the middle of it returns nil, and you do not catch the panic.

huangapple
  • 本文由 发表于 2014年9月27日 04:51:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/26068116.html
匿名

发表评论

匿名网友

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

确定