一般来说,您不应该对陷入严重停机的程序执行任何操作,但在某些情况下您可能需要从停机中恢复。例如,如果 Web 服务器遇到重大意外问题,它必须在崩溃之前关闭所有连接。如果您什么都不做,客户端将处于等待状态。如果Web服务器还处于开发阶段,服务器还可以将异常信息反馈给Web服务器。客户端对于调试很有用。
尖端
在其他语言中,停机通常以异常的形式存在。底层抛出异常,上层逻辑通过try/catch机制捕获异常。未捕获的严重异常会导致停机。捕获的异常可以被忽略,代码继续执行。执行。
Go语言没有异常系统。使用panic来触发停机类似于在其他语言中抛出异常。其中recover宕机恢复机制对应其他语言中的try/catch机制。
允许程序继续运行,即使它崩溃了
以下代码实现 ProtectRun() 函数。该函数在闭包后传递一个匿名函数或执行函数。如果您的接收函数以任何方式发生恐慌,您可以打印崩溃错误并允许后续代码。代码继续运行没有问题。整个过程崩溃了。
保护正在运行的功能。
package main
import (
"fmt"
"runtime"
)
// パニック時に渡すコンテキスト情報
type panicContext struct {
function string // 関数名
}
// 保護された方法で関数を実行する
func ProtectRun(entry func()){
// 遅延処理関数
defer func(){
// パニックで渡されたコンテキストを取得して出力
error:= recover()
switch err.(type){
case runtime.Error:// 実行時エラー
fmt.Println("runtime error:", err)
default:// 実行時エラー以外
fmt.Println("error:", err)
}
}()
entry()
}
func main(){
fmt.Println("動作前")
// 手動エラーの実行を許可
ProtectRun(func() {
fmt.Println("手動パニックの前")
// パニックでコンテキストを渡す
panic(&panicContext {
"手動によるパニックの発生",
})
fmt.Println("手動パニックの後")
})
// ヌルポインターアクセスのエラーを意図的に引き起こす
ProtectRun(func() {
fmt.Println("割り当てパニックの前")
var a *int
*a = 1
fmt.Println("割り当てパニックの後")
})
fmt.Println("実行後")
} 代码输出结果:
動作前
手動パニックの前
手動によるパニックの発生
割り当てパニックの前
runtime error: runtime error: invalid memory address or nil pointer dereference
実行後
代码解释:
- 第 9 行声明了一个结构体,用于描述错误并存储执行错误的函数。
- 第 17 行使用 defer 来推迟闭包的执行。如果恐慌导致崩溃,则 ProtectRun() 函数将完成执行并在调用 defer 后关闭。
- 第20行,recover()获取panic传递的参数。
- 第 22 行使用 switch 对 err 变量执行类型断言。
- 如果错误是运行时层抛出的运行时错误,例如空指针访问或除数为 0,则第 23 行将打印运行时错误。
- 第 25 行的另一个错误打印了传递的错误数据。
- 在第 44 行,使用恐慌手动触发错误并传递包含该信息的结构。此时,recover 检索并输出结构信息。
- 第57行,模拟代码中空指针分配引起的错误被运行时层抛出,并被ProtectRun()函数的cover()函数捕获。
恐慌与恢复之间的关系
恐慌与恢复的结合具有以下特点:
- 发生恐慌,但无法恢复,程序崩溃。
- 恐慌和恢复随之而来。程序就不会下去了。执行相应的延迟后,从停机点退出当前函数并继续执行。
尖端
虽然panic/recovery可以模拟其他语言中的异常机制,但不建议在编写常规函数时频繁使用该功能。
由panic触发的defer函数可以不断调用panic并抛出更多错误,直到整个程序崩溃。
如果要在捕获错误时设置当前函数的返回值,可以使用命名返回值方法直接设置返回值。




![2021 年如何设置 Raspberry Pi Web 服务器 [指南]](https://i0.wp.com/pcmanabu.com/wp-content/uploads/2019/10/web-server-02-309x198.png?w=1200&resize=1200,0&ssl=1)

