1、recovery捕获异常

代码在运行的时候,总会遇到错误。有的时候我们会希望程序遇到错误以后继续运行后面的流程,而不是直接异常退出。在Python中,使用try except组合实现这种需求,代码如下”

s = 0
try:
# 用5除以0,会造成计算结果异常
ret = 5/s
print("运行结果是 {}".format(ret))

except Exception as e:
print("我发现了异常 {}".format(e))

print("我还能继续运行到程序结束")

运行结果

% python main.py 
我发现了异常 division by zero
我还能继续运行到程序结束

Go中没有类似try except这种语法,我们使用内置函数recovery()来替代except捕获异常,要注意recovery()必须与延迟执行函数defer()一起使用。代码如下:

package main

import "fmt"

func calc(s int) {
// 定义一个延迟的匿名函数并运行
defer func() {
// 捕获异常,并赋值给变量。相当于python中except部分的功能
err := recover()
if err != nil {
fmt.Println("我发现了异常: ", err)
}
}()

ret := 5 / s
fmt.Println("运行结果是: ", ret)
}

func main() {

calc(0)

fmt.Println("我还能继续运行到程序结束")
}

运行结果

% go run main.go
我发现了异常: runtime error: integer divide by zero
我还能继续运行到程序结束


2、panic触发异常

除了系统判断出来的程序异常外,我们也会有需求可以自己主动抛出异常来终止程序或进行错误预警。在python中,我们通过raise关键字来实现这个需求,代码如下:

s = 5
try:
ret = int(5/s)
# 程序没错,我也可以自己触发异常
raise Exception("运行结果< {} >是正确的,但我就想抛个异常出来".format(ret))

except Exception as e:
print("我发现了异常: {}".format(e))

print("我还能继续运行到程序结束")

运行结果

% python main.py
我发现了异常 运行结果< 1 >是正确的,但我就想抛个异常出来
我还能继续运行到程序结束

在Go中,我们通过panic来实现类似的效果

package main

import "fmt"

func calc(s int) {
// 定义一个延迟执行的匿名函数
defer func() {
// 捕获异常,并赋值给变量。相当于python中except部分的功能
if err := recover(); err != nil {
fmt.Println("我发现了异常: ", err)
}
}()

ret := 5 / s
fmt.Println("运行结果是: ", ret)
// 主动抛出异常信息,会被recover()捕获到,相当于python中raise关键字的作用
panic("运行结果是正确的,但我就想抛个异常出来")
}

func main() {

calc(5)

fmt.Println("我还能继续运行到程序结束")
}

运行结果

% go run main.go
运行结果是: 1
我发现了异常: 运行结果是正确的,但我就想抛个异常出来
我还能继续运行到程序结束


3、errors

虽然recover()和panic()组合可以实现类似于try..except的效果。但是Go其实不建议轻易使用panic抛异常的方式。推荐的做法是利用glang的函数可以返回多个值的特性。在返回执行的结果的同时,使用内置的错误类型errors描述函数的执行状态。

package main

import (
"errors"
"fmt"
)

// 返回值中包含error类型的数据
func calc(s int) (int, error) {
ret := 5 / s

if s > 1 {
// 定义error类型的描述内容并赋值
WgwAngry := errors.New(fmt.Sprintf("参数大于 1 就不行,现在传输的是 %d", s))
// 将运行结果置为0并将定义的错误描述返回给调用方
return 0, WgwAngry
}

// 未出现异常或错误,error对应的值返回nil即可
return ret, nil

}

func main() {
// 判断函数执行结果中,是否存在错误描述
if r, err := calc(5); err != nil {
// 打印自定义的错误信息
fmt.Println("自定义错误提示: ", err)
} else {
fmt.Println("程序运行结果:", r)
}
}

运行结果

% go run main.go
自定义错误提示: 参数大于 1 就不行,现在传输的是 5