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

一、背景

在日常编写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

你可能感兴趣的:(Go语言的错误&异常处理机制及其应用)