很多刚从 Java 等语言转到 Go 的开发者,第一处不适应往往不是语法,而是错误处理:没有 try-catch,问题都通过返回值显式传递。放到 Debian 环境里,这套机制本身并不会变化,但在日常写服务、命令行工具或系统脚本时,是否把错误定义清楚、判断到位,直接影响排查效率和代码可维护性。
下面按 Go 项目里最常见的几步来梳理:先看 error 的基本约定,再看如何定义可复用错误、怎样在调用方做标准检查,以及什么时候该用 errors.Is()、errors.As() 和 fmt.Errorf() 补充上下文。读完后,你可以快速判断一段 Go 代码的错误处理是否合格。
Go 的错误处理为什么是返回值模式
在 Go 语言里,错误处理没有像 Java 那样的 try-catch,而是直接通过返回值来传递。函数如果遇到问题,就返回一个 error 类型的值;这个 error 是一个接口,只要求实现一个 Error() string 方法,用来返回错误描述。
这也是 Go 项目里最常见的约定:正常结果和错误一起返回,调用方必须显式判断。对 Debian 下的 Go 开发来说,这一点和其他 Linux 发行版、macOS 或 Windows 没有区别,关键不在系统,而在代码习惯。
先定义可复用的错误变量
如果某种错误需要在多个地方复用,通常会先定义一个错误变量,也就是常说的哨兵错误:
var ErrExample = errors.New("这是一个示例错误")
这样做有两个直接好处。第一,避免每次都创建新的错误对象;第二,后续可以围绕同一个错误值做判断,而不是到处比较字符串内容。对需要稳定分支处理的错误场景,这种写法比临时拼接文案更可靠。
函数如何返回错误,调用方又该怎么接
Go 的惯用写法,是让函数把业务结果和 error 一起返回。成功时 error 为 nil,失败时返回具体错误:

func exampleFunction() (int, error) {
// ... 这里是一些代码逻辑
if someCondition {
return 0, ErrExample
}
// ... 其他代码逻辑
return result, nil
}
这里的重点不是语法本身,而是约定非常明确:只要返回了错误,调用方就应该优先处理错误,而不是继续假定结果可用。
对应到调用侧,最常见也最重要的模式就是 if err != nil:
result, err := exampleFunction()
if err != nil {
fmt.Println("发生错误:", err)
} else {
fmt.Println("结果:", result)
}
这种检查几乎遍布每个 Go 代码文件。它看起来比异常机制更显式,也稍显啰嗦,但优点是控制流清楚,读代码时很容易看出哪一步可能失败、失败后如何处理。
需要区分错误类型时,用 errors.Is() 和 errors.As()
当项目开始变复杂,仅靠 err != nil 往往还不够。你可能需要判断“是不是某个已知错误”,或者“能不能把它还原成某种自定义错误类型”,这时就该用 errors.Is() 和 errors.As():

if errors.Is(err, ErrExample) {
fmt.Println("发生了示例错误")
}
var customErr *CustomError
if errors.As(err, &customErr) {
fmt.Println("发生了自定义错误:", customErr)
}
errors.Is() 适用于判断错误链中是否包含某个特定错误,典型场景就是检查哨兵错误;errors.As() 则用于提取错误链中的特定类型,适合需要读取更多字段信息的自定义错误。
这两个函数是 Go 1.13 引入的。实际项目里,优先使用它们,通常比手动比较错误字符串或自行逐层拆解错误更稳妥,也更符合当前 Go 社区的通用写法。
补充排查信息时,用 fmt.Errorf() 包装上下文
如果只返回一个很短的错误描述,到了上层调用链,往往很难判断问题究竟出在哪里。这时可以用 fmt.Errorf() 在错误信息里带上函数名、操作步骤或关键参数:
if someCondition {
return 0, fmt.Errorf("exampleFunction: 发生错误")
}
这种方式的价值在于,它能把“错误发生了”进一步变成“错误发生在什么位置、哪个动作中”,排查时会快很多。
原文还提到,Go 1.20 之后可以配合 %w 包装错误,以保留原始错误链。这里不展开细节,但要记住一点:当你既想补充上下文、又不想丢失底层错误信息时,错误包装会比单纯改写文本更合适。
Debian 下写 Go 时,错误处理的落点其实只有一个
回到标题里的问题,Debian 并不会改变 Go 的错误处理模型。真正需要建立的是一套稳定习惯:先为可识别场景定义错误,函数返回 (result, error),调用方立即检查,必要时再用 errors.Is()、errors.As() 做精细判断,并用 fmt.Errorf() 补足上下文。
在实际项目中,错误处理当然可能继续延伸到日志记录、重试策略和上下文传递,但底层原则并没有变。只要把“返回错误”和“立即处理错误”坚持下来,Go 代码的可读性和可维护性通常都会明显提升。









