第六章:错误处理 2.错误处理 --Go 语言轻松入门

发布于:2024-12-07 ⋅ 阅读:(127) ⋅ 点赞:(0)

在 Go 语言中,错误处理是一个非常重要的主题。Go 采用了一种简单但强大的方式来处理错误:函数通常返回一个 error 类型的值,调用者可以检查这个值是否为 nil 来判断是否有错误发生。如果发生了错误,可以通过 error 接口获取错误信息。

下面是一些常见的错误处理模式和最佳实践:

1. 基本错误处理

最基本的错误处理模式是检查函数返回的 error 是否为 nil。如果不为 nil,则表示有错误发生。

package main

import (
	"errors"
	"fmt"
)

// divide 函数用于执行两个整数的除法操作。
// 它接受两个整数参数 a 和 b,返回两者的商和一个错误。
// 如果除数 b 为零,函数将返回一个错误,说明除零操作是不允许的。
func divide(a, b int) (int, error) {
	if b == 0 {
		return 0, errors.New("division by zero")
	}
	return a / b, nil
}

func main() {
	// 调用 divide 函数进行除法操作。
	// 这里传入的参数是 10 和 0,意在测试函数如何处理除零的情况。
	result, err := divide(10, 0)
	if err != nil {
		// 如果 divide 函数返回了一个错误,这里将输出错误信息。
		fmt.Println("Error:", err)
	} else {
		// 如果 divide 函数没有返回错误,这里将输出计算结果。
		fmt.Printf("Result: %d\n", result)
	}
}

在这里插入图片描述

2. 使用 fmt.Errorf 创建格式化错误

fmt.Errorf 可以用来创建带有格式化字符串的错误。

package main

import (
	"fmt"
)

// compute 函数计算两个整数的和。
// 参数:
//
//	a - 第一个整数。
//	b - 第二个整数。
//
// 返回值:
//
//	两个整数的和。
//	如果 b 为负数,则返回错误。
func compute(a, b int) (int, error) {
	if b < 0 {
		return 0, fmt.Errorf("negative value for b: %d", b)
	}
	// 进行计算...
	return a + b, nil
}

func main() {
	result, err := compute(10, -5)
	if err != nil {
		fmt.Println("Error:", err)
	} else {
		fmt.Printf("Result: %d\n", result)
	}
}

在这里插入图片描述

3. 自定义错误类型

你可以定义自己的错误类型,并实现 error 接口。

package main

import (
	"fmt"
)

// MyError 是一个自定义错误类型,包含错误消息和错误代码。
type MyError struct {
	Message string
	Code    int
}

// Error 实现了 error 接口,返回错误消息。
func (e *MyError) Error() string {
	return e.Message
}

// doSomething 模拟一个可能会产生错误的函数。
// 返回一个指向 MyError 的指针,表示发生错误。
func doSomething() error {
	return &MyError{"something went wrong", 404}
}

func main() {
	// 调用 doSomething 函数并检查是否有错误。
	err := doSomething()
	// 如果发生错误,打印错误消息。
	if err != nil {
		fmt.Println("Error:", err)
	}
}

在这里插入图片描述

4. 错误包装与解包

从 Go 1.13 开始,标准库提供了 errors.Iserrors.As 函数来处理被包装的错误。

package main

import (
	"errors"
	"fmt"
)

// ErrNotFound 是一个预定义的错误,表示资源未找到。
var ErrNotFound = errors.New("not found")

// fetchResource 尝试获取指定ID的资源。
// 如果资源不存在,返回一个带有详细信息的错误。
func fetchResource(id string) error {
	if id == "missing" {
		return fmt.Errorf("resource with ID %s not found: %w", id, ErrNotFound)
	}
	return nil
}

func main() {
	// 调用 fetchResource 函数并检查返回的错误。
	err := fetchResource("missing")
	// 如果错误是 ErrNotFound,打印“资源未找到”。
	if errors.Is(err, ErrNotFound) {
		fmt.Println("Resource not found")
	} else if err != nil {
		// 如果是其他类型的错误,打印“发生意外错误”并显示错误详情。
		fmt.Println("An unexpected error occurred:", err)
	}
}

在这里插入图片描述

5. 使用 deferrecover 处理 panic

对于运行时异常(panic),可以使用 deferrecover 来捕获并处理。

package main

import "fmt"

// safeDivide 安全地执行除法操作。
// 参数:
//
//	a: 被除数
//	b: 除数
//
// 返回值:
//
//	result: 除法结果
//	err: 如果发生错误,返回错误信息
func safeDivide(a, b int) (result int, err error) {
	// 使用 defer 和 recover 捕获并处理 panic
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("panic recovered: %v", r)
		}
	}()

	// 如果除数为 0,触发 panic
	if b == 0 {
		panic("division by zero")
	}
	// 正常情况下返回除法结果
	return a / b, nil
}

func main() {
	// 调用 safeDivide 函数并检查返回的错误
	result, err := safeDivide(10, 0)
	if err != nil {
		// 如果有错误,打印错误信息
		fmt.Println("Error:", err)
	} else {
		// 如果没有错误,打印除法结果
		fmt.Printf("Result: %d\n", result)
	}
}

在这里插入图片描述

6. 使用 log 包记录错误

在实际应用中,你可能希望将错误记录到日志文件中,而不是直接打印到控制台。

package main

import (
	"errors"
	"log"
	"os"
)

// divide 函数用于执行两个整数的除法操作。
// 它接受两个整数参数 a 和 b,返回两者的商和一个错误。
// 如果除数 b 为零,函数将返回一个错误,说明除零操作是不允许的。
func divide(a, b int) (int, error) {
	if b == 0 {
		return 0, errors.New("division by zero")
	}
	return a / b, nil
}

func main() {
	// 打开或创建日志文件,模式为追加写入,权限为 0666
	logFile, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		// 如果打开日志文件失败,记录致命错误并退出程序
		log.Fatalf("Failed to open log file: %v", err)
	}
	// 确保在程序结束时关闭日志文件
	defer logFile.Close()

	// 设置日志输出到文件
	log.SetOutput(logFile)

	// 调用 divide 函数并检查返回的错误
	result, err := divide(10, 0)
	if err != nil {
		// 如果有错误,记录错误信息
		log.Println("Error:", err)
	} else {
		// 如果没有错误,记录除法结果
		log.Printf("Result: %d\n", result)
	}
}

在这里插入图片描述

这些示例展示了 Go 中几种常见的错误处理方法。通过这些方法,你可以有效地管理和处理程序中的错误,提高代码的健壮性和可维护性。


网站公告

今日签到

点亮在社区的每一天
去签到