Go语言的错误处理机制:
type error interface {
Error() string
}
defer func() {
// 延迟执行的代码
}()
// 恢复panic func recover() interface{}
### 2. 应用场景
- **error类型**:数据库连接失败、文件读写错误
- **defer语句**:资源清理(关闭文件、释放锁、数据库连接)
- **panic/recover**:处理不可恢复的错误(如数组越界)
### 3. 编程实例
```go
package main
import (
"errors"
"fmt"
"os"
"time"
)
// 自定义错误类型
type BusinessError struct {
Code int
Message string
Time time.Time
}
func (e *BusinessError) Error() string {
return fmt.Sprintf("错误代码: %d, 消息: %s, 时间: %s",
e.Code, e.Message, e.Time.Format("2006-01-02 15:04:05"))
}
// 数据库操作模拟
func queryDatabase(userId int) (string, error) {
if userId <= 0 {
return "", &BusinessError{
Code: 400,
Message: "无效的用户ID",
Time: time.Now(),
}
}
// 模拟数据库连接失败
if userId == 999 {
return "", errors.New("数据库连接超时")
}
return "用户数据", nil
}
// 文件操作:使用defer确保资源释放
func readFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("打开文件失败: %w", err)
}
defer file.Close() // 确保文件会被关闭
// 模拟文件读取
buf := make([]byte, 100)
_, err = file.Read(buf)
if err != nil {
return fmt.Errorf("读取文件失败: %w", err)
}
return nil
}
// panic/recover示例:处理数组越界
func safeAccess(arr []int, index int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("发生panic: %v", r)
}
}()
result = arr[index] // 可能触发panic
return result, nil
}
func main() {
// 错误处理示例
fmt.Println("=== 数据库查询测试 ===")
// 正常查询
data, err := queryDatabase(1)
if err != nil {
fmt.Println("查询失败:", err)
} else {
fmt.Println("查询结果:", data)
}
// 无效ID查询
_, err = queryDatabase(-1)
if err != nil {
fmt.Println("查询失败:", err)
}
// 数据库连接失败
_, err = queryDatabase(999)
if err != nil {
fmt.Println("查询失败:", err)
}
// defer使用示例
fmt.Println("\n=== defer使用示例 ===")
func() {
defer fmt.Println("1. 第一个defer")
defer fmt.Println("2. 第二个defer")
fmt.Println("3. 函数体")
}()
// panic/recover示例
fmt.Println("\n=== panic/recover测试 ===")
arr := []int{1, 2, 3}
// 正常访问
result, err := safeAccess(arr, 1)
if err != nil {
fmt.Println("访问失败:", err)
} else {
fmt.Println("访问成功:", result)
}
// 越界访问
result, err = safeAccess(arr, 10)
if err != nil {
fmt.Println("访问失败:", err)
} else {
fmt.Println("访问成功:", result)
}
fmt.Println("程序继续执行...")
}
package main
import (
"errors"
"fmt"
"os"
)
func readConfig() error {
err := readFile("config.txt")
if err != nil {
return fmt.Errorf("读取配置文件失败: %w", err)
}
return nil
}
func readFile(filename string) error {
_, err := os.Stat(filename)
if err != nil {
return fmt.Errorf("检查文件状态失败: %w", err)
}
return nil
}
func main() {
err := readConfig()
if err != nil {
fmt.Println("发生错误:", err)
// 解包错误链
var pathError *os.PathError
if errors.As(err, &pathError) {
fmt.Printf("路径错误: %s\n", pathError.Path)
}
}
}
package main
import "fmt"
// defer修改返回值
func deferReturn() (result int) {
defer func() {
result++ // 修改命名返回值
}()
return 10 // 实际返回11
}
// defer与recover结合
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("除法出错: %v", r)
}
}()
result = a / b
return result, nil
}
func main() {
// defer修改返回值
fmt.Println("deferReturn:", deferReturn()) // 输出11
// 安全的除法
result, err := safeDivide(10, 0)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("结果:", result)
}
}
本课时我们学习了: