Menu
CoddyTech

使用 `recover`

本课属于 Coddy GO 学习旅程的“逻辑与流程”单元。第 43 课,共 68 课。

虽然 panic 会立即停止程序,但 Go 提供了一种通过 recover 函数重新获得控制权的方法。recover 函数可以捕获 panic 并妥善处理,防止整个程序崩溃。

不过,recover 有一个非常具体的要求:它只能在延迟函数中使用。发生 panic 时,Go 会在程序终止前执行所有延迟函数,这让 recover 有机会拦截 panic:

func riskyFunction() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()
    
    panic("something went wrong!")
}

recover 函数会返回传递给 panic 的值。如果没有发生 panic,则返回 nil。这样你就可以检查是否发生了 panic,并采取适当的操作,例如记录错误或执行清理操作。

和 panic 一样,在 Go 中也应谨慎使用 recover。它最常见于 Web 服务器等场景,在这些场景中,你希望避免单个请求触发的 panic 导致整个服务器崩溃,让服务器可以继续处理其他请求。

challenge icon

挑战

简单

构建一个 Web 服务器请求处理程序,使用 recover 优雅地处理 panic,防止整个服务器崩溃。本挑战将展示如何在延迟执行的函数中使用 recover 捕获 panic,并保持服务器稳定。

你将收到两个输入:

  • 一个包含请求详情的字符串,格式为 "endpoint,method,action"(例如:"/api/users,GET,process")
  • 一个包含服务器配置的字符串,格式为 "server_name,max_requests"(例如:"WebServer,100")

你的任务是:

  1. 通过按逗号拆分第一个输入,获取 endpoint、method 和 action
  2. 通过按逗号拆分第二个输入,获取服务器名称和最大请求数
  3. 将最大请求数字符串转换为整数
  4. 创建一个名为 handleRequest 的函数,将 endpoint、method、action 和服务器名称作为参数
  5. 在 handleRequest 中添加一个延迟执行的函数,使用 recover 捕获任何 panic:
    • 如果恢复了 panic(recover 返回非 nil 值),打印:"Server [server_name] recovered from panic: [panic_value]"
    • 处理完 panic 后,打印:"Request handling completed safely"
  6. 在延迟执行的函数之后,根据 action 模拟请求处理:
    • 如果 action 是 "process":打印 "Processing [method] request to [endpoint]"
    • 如果 action 是 "panic_nil":打印 "Attempting dangerous operation",然后调用 panic("nil pointer access")
    • 如果 action 是 "panic_overflow":打印 "Attempting resource allocation",然后调用 panic("memory overflow")
    • 如果 action 是 "panic_timeout":打印 "Attempting database connection",然后调用 panic("connection timeout")
    • 对于其他任何 action:打印 "Unknown action: [action]",然后调用 panic("invalid action")
  7. 在 main 函数中,打印服务器启动消息:"Starting [server_name] with max [max_requests] requests"
  8. 使用解析后的参数调用 handleRequest 函数
  9. 函数调用后,打印服务器状态:"Server [server_name] is still running"
  10. 最后,打印摘要:
    • "Server Summary:"
    • "Name: [server_name]"
    • "Max Requests: [max_requests]"
    • "Last Request: [method] [endpoint]"
    • "Action Performed: [action]"
    • "Status: Operational"

使用 strings 包按逗号拆分输入字符串,并使用 strconv 包将最大请求数字符串转换为整数。本挑战将展示 recover 如何帮助服务器优雅地处理意外的 panic,防止单个请求失败导致整个系统停止运行。

亲手试试

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	// 读取输入
	var requestDetails string
	var serverConfig string
	fmt.Scanln(&requestDetails)
	fmt.Scanln(&serverConfig)
	
	// 解析请求详情
	requestParts := strings.Split(requestDetails, ",")
	endpoint := requestParts[0]
	method := requestParts[1]
	action := requestParts[2]
	
	// 解析服务器配置
	configParts := strings.Split(serverConfig, ",")
	serverName := configParts[0]
	maxRequests, _ := strconv.Atoi(configParts[1])
	
	// TODO: 在下方编写代码
	// 创建带有 recover 机制的 handleRequest 函数
	// 输出服务器启动信息
	// 调用 handleRequest 函数
	// 输出服务器状态和摘要
	
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

逻辑与流程中的所有课

自己练习: Go 在线编译器