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

2025-08-18 22:50

本文主要是介绍Go之errors.New和fmt.Errorf 的区别小结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了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 mahttp://www.chinasem.cnin

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("phperr: %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("错DcBsXTjG误信息:", 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 strujsct {
    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", validationErrpython.Field)
    }
    
    if businessErr, ok := err.(*BusinessError); ok {
        fmt.Printf("   这是一个业务错误,错误码: %d\n", businessErr.Code)
    }
}

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

这篇关于Go之errors.New和fmt.Errorf 的区别小结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155801

相关文章

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

MySQL中VARCHAR和TEXT的区别小结

《MySQL中VARCHAR和TEXT的区别小结》MySQL中VARCHAR和TEXT用于存储字符串,VARCHAR可变长度存储在行内,适合短文本;TEXT存储在溢出页,适合大文本,下面就来具体的了解... 目录一、VARCHAR 和 TEXT 基本介绍1. VARCHAR2. TEXT二、VARCHAR

全网最全Tomcat完全卸载重装教程小结

《全网最全Tomcat完全卸载重装教程小结》windows系统卸载Tomcat重新通过ZIP方式安装Tomcat,优点是灵活可控,适合开发者自定义配置,手动配置环境变量后,可通过命令行快速启动和管理... 目录一、完全卸载Tomcat1. 停止Tomcat服务2. 通过控制面板卸载3. 手动删除残留文件4.

Python打包成exe常用的四种方法小结

《Python打包成exe常用的四种方法小结》本文主要介绍了Python打包成exe常用的四种方法,包括PyInstaller、cx_Freeze、Py2exe、Nuitka,文中通过示例代码介绍的非... 目录一.PyInstaller11.安装:2. PyInstaller常用参数下面是pyinstal

Go语言中json操作的实现

《Go语言中json操作的实现》本文主要介绍了Go语言中的json操作的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录 一、jsOChina编程N 与 Go 类型对应关系️ 二、基本操作:编码与解码 三、结构体标签(Struc

使用Go调用第三方API的方法详解

《使用Go调用第三方API的方法详解》在现代应用开发中,调用第三方API是非常常见的场景,比如获取天气预报、翻译文本、发送短信等,Go作为一门高效并发的编程语言,拥有强大的标准库和丰富的第三方库,可以... 目录引言一、准备工作二、案例1:调用天气查询 API1. 注册并获取 API Key2. 代码实现3

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

python中getsizeof和asizeof的区别小结

《python中getsizeof和asizeof的区别小结》本文详细的介绍了getsizeof和asizeof的区别,这两个函数都用于获取对象的内存占用大小,它们来自不同的库,下面就来详细的介绍一下... 目录sys.getsizeof (python 内置)pympler.asizeof.asizeof

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

mybatis映射器配置小结

《mybatis映射器配置小结》本文详解MyBatis映射器配置,重点讲解字段映射的三种解决方案(别名、自动驼峰映射、resultMap),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定... 目录select中字段的映射问题使用SQL语句中的别名功能使用mapUnderscoreToCame