Go之errors.New和fmt.Errorf 的区别小结

 更新时间:2025年08月18日 11:57:37   作者:太凉  
本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

error的基本用法

1. 获取错误信息

package main

import (
    "errors"
    "fmt"
)

func main() {
    // 创建错误
    err := errors.New("文件不存在")
    
    // 获取错误信息
    errorMessage := err.Error()
    fmt.Println("错误信息:", errorMessage) // 输出: 错误信息: 文件不存在
    
    // 直接打印错误
    fmt.Println("直接打印:", err) // 输出: 直接打印: 文件不存在
}

2. 在条件判断中使用

package main

import (
    "errors"
    "fmt"
)

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        // 获取错误信息进行判断
        if err.Error() == "除数不能为零" {
            fmt.Println("检测到除零错误")
        }
        
        // 打印错误信息
        fmt.Println("错误:", err.Error())
        return
    }
    fmt.Println("结果:", result)
}

基本区别

1.函数签名

// errors.New - 只接受字符串
func New(text string) error

// fmt.Errorf - 接受格式化字符串和参数
func Errorf(format string, a ...interface{}) error

2.使用场景

package main

import (
    "errors"
    "fmt"
)

func main() {
    // errors.New - 简单静态错误
    err1 := errors.New("文件不存在")
    fmt.Println(err1)
    
    // fmt.Errorf - 动态格式化错误
    filename := "config.txt"
    err2 := fmt.Errorf("文件 %s 不存在", filename)
    fmt.Printf("err: %v \n", err.Error())
}

详细对比

1. 静态错误 vs 动态错误

package main

import (
    "errors"
    "fmt"
)

// 使用 errors.New - 适合静态错误
var (
    ErrNotFound = errors.New("记录未找到")
    ErrInvalidInput = errors.New("无效输入")
    ErrTimeout = errors.New("操作超时")
)

// 使用 fmt.Errorf - 适合动态错误
func validateAge(age int) error {
    if age < 0 {
        return fmt.Errorf("年龄不能为负数: %d", age)
    }
    if age > 150 {
        return fmt.Errorf("年龄不能超过150岁: %d", age)
    }
    return nil
}

func main() {
    // 静态错误
    fmt.Println(ErrNotFound)
    
    // 动态错误
    err := validateAge(-5)
    fmt.Println(err)
}

2. 错误比较

package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("记录未找到")

func main() {
    // errors.New 创建的错误可以用于比较
    err1 := ErrNotFound
    err2 := ErrNotFound
    
    fmt.Println(err1 == err2) // true
    
    // fmt.Errorf 创建的错误每次都是新的
    err3 := fmt.Errorf("记录未找到")
    err4 := fmt.Errorf("记录未找到")
    
    fmt.Println(err3 == err4) // false
}

3. 错误包装

package main

import (
    "errors"
    "fmt"
)

func processFile(filename string) error {
    // 模拟文件操作错误
    originalErr := errors.New("权限不足")
    
    // 使用 fmt.Errorf 包装错误
    return fmt.Errorf("处理文件 %s 失败: %v", filename, originalErr)
}

func main() {
    err := processFile("config.txt")
    fmt.Println(err) // 输出: 处理文件 config.txt 失败: 权限不足
}

实际应用场景

1. 使用 errors.New 的场景

package main

import (
    "errors"
    "fmt"
)

// 定义包级别的错误常量
var (
    ErrUserNotFound = errors.New("用户不存在")
    ErrInvalidPassword = errors.New("密码错误")
    ErrDatabaseConnection = errors.New("数据库连接失败")
)

func authenticateUser(userID string, password string) error {
    if userID == "" {
        return ErrUserNotFound
    }
    
    if password == "" {
        return ErrInvalidPassword
    }
    
    // 验证逻辑...
    return nil
}

func main() {
    err := authenticateUser("", "123456")
    if err == ErrUserNotFound {
        fmt.Println("用户不存在")
    } else if err == ErrInvalidPassword {
        fmt.Println("密码错误")
    }
}

2. 使用 fmt.Errorf 的场景

package main

import (
    "fmt"
    "strconv"
)

func parseUserID(userIDStr string) (int, error) {
    userID, err := strconv.Atoi(userIDStr)
    if err != nil {
        return 0, fmt.Errorf("解析用户ID失败: %v", err)
    }
    
    if userID <= 0 {
        return 0, fmt.Errorf("用户ID必须大于0,当前值: %d", userID)
    }
    
    return userID, nil
}

func getUserInfo(userIDStr string) error {
    userID, err := parseUserID(userIDStr)
    if err != nil {
        return fmt.Errorf("获取用户信息失败: %v", err)
    }
    
    fmt.Printf("用户ID: %d\n", userID)
    return nil
}

func main() {
    err := getUserInfo("abc")
    if err != nil {
        fmt.Println("错误:", err)
    }
}

自定义错误类型

1.基本用法

package main

import "fmt"

// 自定义错误类型
type ValidationError struct {
    Field   string
    Message string
}

// 实现 Error() 方法
func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证失败: 字段 '%s' - %s", e.Field, e.Message)
}

func validateUser(name string) error {
    if name == "" {
        return &ValidationError{
            Field:   "name",
            Message: "用户名不能为空",
        }
    }
    return nil
}

func main() {
    err := validateUser("")
    if err != nil {
        // 获取错误信息
        fmt.Println("错误信息:", err.Error())
        
        // 类型断言获取详细信息
        if validationErr, ok := err.(*ValidationError); ok {
            fmt.Printf("字段: %s, 消息: %s\n", validationErr.Field, validationErr.Message)
        }
    }
}

2.自定义错误类型示例

package main

import (
    "fmt"
    "time"
)

// 1. 基础自定义错误类型
type ValidationError struct {
    Field   string
    Message string
    Value   interface{}
}

// 实现 error 接口
func (e *ValidationError) Error() string {
    return fmt.Sprintf("验证失败: 字段 '%s' 的值 '%v' - %s", e.Field, e.Value, e.Message)
}

// 2. 业务错误类型
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"))
}

// 3. 网络错误类型
type NetworkError struct {
    URL     string
    Status  int
    Message string
}

func (e *NetworkError) Error() string {
    return fmt.Sprintf("网络请求失败: %s (状态码: %d) - %s", e.URL, e.Status, e.Message)
}

// 4. 复合错误类型
type CompositeError struct {
    Errors []error
    Context string
}

func (e *CompositeError) Error() string {
    if len(e.Errors) == 0 {
        return fmt.Sprintf("复合错误: %s", e.Context)
    }
    
    result := fmt.Sprintf("复合错误 [%s]:\n", e.Context)
    for i, err := range e.Errors {
        result += fmt.Sprintf("  %d. %s\n", i+1, err.Error())
    }
    return result
}

// 5. 带错误码的错误类型
type CodedError struct {
    Code    int
    Message string
    Details map[string]interface{}
}

func (e *CodedError) Error() string {
    if len(e.Details) == 0 {
        return fmt.Sprintf("[%d] %s", e.Code, e.Message)
    }
    return fmt.Sprintf("[%d] %s - 详情: %v", e.Code, e.Message, e.Details)
}

// 使用示例函数
func validateUser(name string, age int) error {
    if name == "" {
        return &ValidationError{
            Field:   "name",
            Message: "用户名不能为空",
            Value:   name,
        }
    }
    
    if age < 0 || age > 150 {
        return &ValidationError{
            Field:   "age",
            Message: "年龄必须在 0-150 之间",
            Value:   age,
        }
    }
    
    return nil
}

func processOrder(orderID string) error {
    if orderID == "" {
        return &BusinessError{
            Code:    1001,
            Message: "订单ID不能为空",
            Time:    time.Now(),
        }
    }
    
    // 模拟网络请求失败
    if orderID == "invalid" {
        return &NetworkError{
            URL:     "https://api.example.com/orders/" + orderID,
            Status:  404,
            Message: "订单不存在",
        }
    }
    
    return nil
}

func complexOperation() error {
    var errors []error
    
    // 模拟多个操作
    if err := validateUser("", 25); err != nil {
        errors = append(errors, err)
    }
    
    if err := processOrder(""); err != nil {
        errors = append(errors, err)
    }
    
    if len(errors) > 0 {
        return &CompositeError{
            Errors:  errors,
            Context: "用户注册操作",
        }
    }
    
    return nil
}

func main() {
    fmt.Println("=== 自定义错误类型示例 ===\n")
    
    // 1. 验证错误示例
    fmt.Println("1. 验证错误:")
    if err := validateUser("", 25); err != nil {
        fmt.Printf("   %s\n", err.Error())
    }
    
    if err := validateUser("张三", 200); err != nil {
        fmt.Printf("   %s\n", err.Error())
    }
    
    // 2. 业务错误示例
    fmt.Println("\n2. 业务错误:")
    if err := processOrder(""); err != nil {
        fmt.Printf("   %s\n", err.Error())
    }
    
    // 3. 网络错误示例
    fmt.Println("\n3. 网络错误:")
    if err := processOrder("invalid"); err != nil {
        fmt.Printf("   %s\n", err.Error())
    }
    
    // 4. 复合错误示例
    fmt.Println("\n4. 复合错误:")
    if err := complexOperation(); err != nil {
        fmt.Printf("   %s\n", err.Error())
    }
    
    // 5. 带错误码的错误示例
    fmt.Println("\n5. 带错误码的错误:")
    codedErr := &CodedError{
        Code:    5001,
        Message: "数据库连接失败",
        Details: map[string]interface{}{
            "host":     "localhost:3306",
            "database": "users",
            "reason":   "连接超时",
        },
    }
    fmt.Printf("   %s\n", codedErr.Error())
    
    // 6. 错误类型检查示例
    fmt.Println("\n6. 错误类型检查:")
    err := validateUser("", 25)
    if validationErr, ok := err.(*ValidationError); ok {
        fmt.Printf("   这是一个验证错误,字段: %s\n", validationErr.Field)
    }
    
    if businessErr, ok := err.(*BusinessError); ok {
        fmt.Printf("   这是一个业务错误,错误码: %d\n", businessErr.Code)
    }
}

到此这篇关于Go之errors.New 和 fmt.Errorf 的区别的文章就介绍到这了,更多相关Go errors.New 和 fmt.Errorf 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言基础for循环语句的用法及示例详解

    Go语言基础for循环语句的用法及示例详解

    这篇文章主要为大家介绍了Go语言基础for循环语句的用法及示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • Go语言操作Excel利器之excelize类库详解

    Go语言操作Excel利器之excelize类库详解

    Excelize是Go语言编写的用于操作Office Excel文档基础库,基于ECMA-376,ISO/IEC 29500国际标准,可以使用它来读取、写入由Excel 2007及以上版本创建的电子表格文档,下面这篇文章主要给大家介绍了关于Go语言操作Excel利器之excelize类库的相关资料,需要的朋友可以参考下
    2022-10-10
  • 一文深入探索Go语言中的循环结构

    一文深入探索Go语言中的循环结构

    在编程中,循环结构扮演着重要的角色,它使我们能够有效地重复执行特定的代码块,以实现各种任务和逻辑,在Go语言中,for 是 Go 中唯一的循环结构,本文将深入探讨Go语言中的for循环类型以及它们的用法
    2023-08-08
  • vscode搭建go开发环境案例详解

    vscode搭建go开发环境案例详解

    对于Visual Studio Code开发工具,有一款优秀的GoLang插件,今天通过本文给大家介绍下vscode搭建go开发环境的详细教程,感兴趣的朋友跟随小编一起看看吧
    2021-12-12
  • 浅谈Go语言多态的实现与interface使用

    浅谈Go语言多态的实现与interface使用

    如果大家系统的学过C++、Java等语言以及面向对象的话,相信应该对多态不会陌生。多态是面向对象范畴当中经常使用并且非常好用的一个功能,它主要是用在强类型语言当中,像是Python这样的弱类型语言,变量的类型可以随意变化,也没有任何限制,其实区别不是很大
    2021-06-06
  • Go语言中break label与goto label的区别

    Go语言中break label与goto label的区别

    这篇文章主要介绍了Go语言中break label与goto label的区别,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • vscode如何debug调试golang代码

    vscode如何debug调试golang代码

    古话说工欲善其事必先利其器,Go语言程序的开发者而言,当下最火的IDE应该非微软的Visual Studio Code莫属,本文主要介绍了vscode如何debug调试golang代码,感兴趣的可以了解一下
    2024-03-03
  • go语言中os包的用法实战大全

    go语言中os包的用法实战大全

    Go在os中提供了文件的基本操作,包括通常意义的打开、创建、读写等操作,除此以外为了追求便捷以及性能上,Go还在io/ioutil以及bufio提供一些其他函数供开发者使用,这篇文章主要给大家介绍了关于go语言中os包用法的相关资料,需要的朋友可以参考下
    2024-02-02
  • Golang http包构建RESTful API的实现

    Golang http包构建RESTful API的实现

    在Go语言中实现RESTful API可以利用标准库net/http提供的功能,它允许你轻松地创建和处理HTTP请求,本文主要介绍了Golang http包构建RESTful API的实现,感兴趣的可以了解一下
    2024-01-01
  • Go语言中日期包(time包)的具体使用

    Go语言中日期包(time包)的具体使用

    本文主要介绍了Go语言中日期包的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05

最新评论