首页 / Go 语言入门教程 / error 接口与错误创建

Go 语言入门教程

error 接口与错误创建

本教程共 80 篇 · 第 51 篇 · 更新于 2026-07-27 · 约 7 分钟阅读

GoGo 入门教程error错误处理errors.Newfmt.Errorf

51. error 接口与错误创建

本节目标:搞懂 Go 的 error 接口,学会用 errors.New 和 fmt.Errorf 创建错误,理解「错误是值」的理念。

error 接口

Go 的错误处理方式和大多数语言不同。没有 try-catch,错误就是普通的返回值。

error 是一个内置接口,只有一个方法:

type error interface {
    Error() string
}

任何实现了 Error() string 方法的类型都能当 error 用。Go 用这种方式把错误变成了值,你可以像处理其他返回值一样处理它。

基本错误处理模式

Go 函数通常把 error 作为最后一个返回值:

package main

import (
    "errors"
    "fmt"
)

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

func main() {
    result, err := Divide(10, 0)
    if err != nil {
        fmt.Println("出错了:", err)
        return
    }
    fmt.Println("结果:", result)
}

这就是 Go 最经典的错误处理模式:

  1. 函数返回 (result, error) 两个值
  2. 成功时 error 为 nil
  3. 失败时 error 不为 nil,result 是零值
  4. 调用方检查 if err != nil
Note

Go 社区有句玩笑话:「如果你能接受 Go 的 if err != nil,你就算入门了。」这种写法确实啰嗦,但好处是每个错误都被显式处理,不会像异常那样被意外忽略。

创建错误:errors.New

errors.New 创建一个简单的错误:

err := errors.New("文件不存在")
fmt.Println(err) // 文件不存在

适合错误信息简单、不需要附加数据的场景。

创建错误:fmt.Errorf

fmt.Errorf 支持格式化,能嵌入变量信息:

package main

import "fmt"

func GetUser(id int) (string, error) {
    if id <= 0 {
        return "", fmt.Errorf("无效的用户ID: %d", id)
    }
    return "Alice", nil
}

func main() {
    _, err := GetUser(-1)
    fmt.Println(err) // 无效的用户ID: -1
}

fmt.Errorferrors.New 更常用,因为错误信息里通常需要包含上下文数据。

错误是值

Go 的设计理念是「错误是值」。这意味着:

  1. 错误不是特殊的东西,就是一个普通的返回值
  2. 你可以选择处理它、传递它、或者忽略它(但不推荐忽略)
  3. 没有隐式的错误传播机制,每一步都要显式处理
// 错误传递:把收到的错误原样返回
func ProcessFile(path string) error {
    data, err := os.ReadFile(path)
    if err != nil {
        return err // 不处理,传给调用方
    }
    // 处理 data...
    return nil
}
Tip

如果你的函数不负责处理某个错误,就把它返回给调用方。让能处理错误的那一层来处理。

常见错误处理方式

直接返回

if err != nil {
    return err
}

添加上下文后返回

if err != nil {
    return fmt.Errorf("读取配置失败: %w", err)
}
Warning

%w 而不是 %v 来包装错误。%w 保留错误链,调用方可以用 errors.Is 检查。%v 只是把错误变成字符串,丢失了类型信息。下一章会详细讲。

记录日志后继续

if err != nil {
    log.Printf("警告: %v", err)
    // 继续执行,不中断
}

终止程序

if err != nil {
    log.Fatal(err) // 打印错误后 os.Exit(1)
}
Note

log.Fatal 只在不可恢复的错误时用,比如配置文件加载失败、数据库连接失败。大部分错误应该返回给调用方处理,不要直接退出程序。

不要忽略错误

Go 编译器不会强制你检查 error 返回值,但忽略错误是坏习惯:

// 坏:忽略了 error
result, _ := SomeFunction()

// 好:至少检查一下
result, err := SomeFunction()
if err != nil {
    return err
}
Warning

_ 忽略 error 时要特别小心。除非你确定错误不重要,否则一定要检查。很多 bug 就是因为忽略了错误返回值。

小结

错误创建和基本处理:

  • error 是一个接口,只有一个 Error() string 方法
  • errors.New 创建简单错误,fmt.Errorf 创建格式化错误
  • 经典模式:if err != nil { return err }
  • %w 包装错误,保留错误链
  • 不要忽略 error 返回值

下一章讲错误包装和 errors.Is/As/Join。