Go语言的错误&异常处理机制及其应用

    科技2025-08-10  11

    一、背景

    在日常编写golang程序或阅读别人的golang代码时,我们总会看到如下的一堆代码块:

    xx, err = func(xx) if err != nil { //do sth. to tackle this problem }

    这种经典的显式错误处理方式,在golang开发中几乎无处不在,了解过golang开发的同学肯定会很熟悉、但同时又可能很痛恨这种麻烦的错误处理方式。

    那么golang语言开发者为什么要这样设计呢?nil的意义是什么?它又有什么有趣的应用?对于这些问题,笔记会在下文逐一介绍。

    二、golang的错误&异常处理机制

    1.错误与异常的区别

    错误:意料之内,可能出的问题, 比如网络连接超时,json解析错误等 异常:意料之外,不应该出的问题,比如空指针异常,下标溢出等异常

    由上可知,错误与异常的区别,主要在于error是否在预料之内。而能否很好地操控与处理预料之内的error,往往能看出一个程序员水平的高低。

    2.golang的两种错误处理方式

    golang有两种错误处理方式,分别是错误返回和捕获异常。

    ①错误返回

    golang 使用error接口作为标准错误接口,在标准库函数中,error通常作为函数的最后一个返回值:

    func func()(xx, err error){ //code return xx, err }

    为了处理预料之内的error,golang强制要求程序员处理错误返回,即我们常见的代码片段:

    xx, err = func(xx) if err != nil { //do sth. to tackle this problem }

    当函数执行正确时,返回的err=nil;若err!=nil,程序员需要编写错误提示等。

    其中nil的含义及作用可见【三、补充】。

    ②异常捕获

    为了处理预料之外的error,golang使用用到了panic、recover两个内置函数和一个关键字defer来处理异常。

    panic——用于抛出异常 recover——捕获异常 defer——声明延迟函数

    golang的异常处理/异常捕获过程,可以简单地概括为:

    在defer声明的延迟函数中,通过recover捕获panic抛出的异常。 (其中defer要在panic之前进行声明)

    例子:使用defer + recover来捕获和处理异常

    package main import ( "fmt" "time" ) func test(){ //使用defer + recover来捕获和处理异常 defer func(){ err := recover() // recover()是go内置函数,可以捕获到异常 if err != nil { //err 不为空 fmt.Println("err=", err) } }()//匿名函数 num1 := 18342026 num2 := 0 res := num1/num2 //异常error fmt.Println("res=", res) } func main(){ test() fmt.Println("func_test done.") }

    3.关于网上对于golang错误处理的吐槽与辩驳

    在许多网络论坛中,不少人吐槽golang的“err != nil”的错误处理方式不够优雅,直言在调用各种库函数时都得添加这一代码片段既显得“啰嗦”,又会影响自己的项目开发效率。

    然而在笔者看来,这却是一种优秀的安全机制,它强制要求程序员处理有可能产生的error,对于维护项目的安全性与健壮性而言十分重要。

    而且,对于熟悉c/c++编程、又觉得java编程比较臃肿的笔者来说,golang的“err != nil”可比java的try catch优雅多了~

    此外,对于不喜欢或想要忽略已知的错误时,也有其他的办法避免“err != nil”的操作,具体可见【三、补充】。

    三、补充

    1.nil的含义

    nil和null类似,都是表示空/零。在Go语言中,布尔类型的"0"(初始值)为false,数值类型的"0"为0,字符串类型的"0"为空字符串"",而指针/切片/映射/通道/函数和接口的"0"即为nil。

    2.如何避免“err != nil”的操作

    虽然预先处理预料之中的错误是一种良好的编程习惯,但有时候因为各种原因也会选择忽略错误(主要是因为懒),而避免“err != nil”的操作笔者目前只用到以下这种方法:

    xx, _ = func(xx)

    也就是用“_”直接忽略了传送的err参数,但如果有时间还是尽量进行错误处理,毕竟golang如此设计的初衷便是让程序员正视错误,并解决错误。

    此外,还有一些有趣的方法可以避免重复的err操作,详情见:如何减少重复err

    Processed: 0.013, SQL: 8