6.Go-错误,defer,panic和recover
6.1.错误
Go语言中使用builtin包下error接口作为错误类型
Go语言中错误都作为方法/函数的返回值
自定义错误类型
//Learn_Go/main.go package main import ( "errors" "fmt" ) func demo(i,k int) (r int, e error) { if k == 0 { e = errors.New("除数不能为0") return } r = i/k return } func main() { //result,error := demo(6,3) result,e := demo(6,0) if e != nil{ fmt.Println("执行错误,错误信息为:",e) //执行错误,错误信息为: 除数不能为0 return } fmt.Println("执行成功,结果:",result) //执行成功,结果: 2 }
6.2.defer
Go语言中defer可以完成延迟功能,当前函数执行完成后执行defer功能
defer最常用的就是关闭连接(数据库,文件等),可以打开连接后紧跟defer进行关闭
(1)Go语言中defer无论写到哪里都是最后执行,不用非要把关闭代码写在最后
//Learn_Go/main.go package main import "fmt" func main() { fmt.Println("打开连接") //defer fmt.Println("关闭连接") defer func() { fmt.Println("关闭连接") //defer执行 }() fmt.Println("进行操作") } //结果 打开连接 进行操作 关闭连接
(2)多个defer
多重defer采用栈结构执行,先产生后执行
在很多代码结构中都可能出现产生多个对象,而程序希望这些对象倒叙关闭,多个defer正好可以解决这个问题
//Learn_Go/main.go package main import "fmt" func main() { fmt.Println("打开连接A") defer fmt.Println("关闭连接A") fmt.Println("打开连接B") defer fmt.Println("关闭连接B") fmt.Println("打开连接C") defer fmt.Println("关闭连接C") fmt.Println("进行操作") } //结果 打开连接A 打开连接B 打开连接C 进行操作 关闭连接C 关闭连接B 关闭连接A
(3)defer和return结合
defer与return同时存在时,要把return理解成两条执行结合,一个指令是给返回值
赋值,另一个指令返回跳出函数
defer和return时整体执行顺序
- 先给返回值赋值
- 执行defer
- 返回跳出函数
(4)没有定义返回值接收变量,执行defer时返回值已经赋值
//Learn_Go/main.go package main import "fmt" func demo() int { i := 1 defer func() { i = i + 2 }() return i } func main() { fmt.Println(demo()) //1 }
(5)声明接收返回值变量,执行defer时修改了返回值内容
//Learn_Go/main.go package main import "fmt" func demo() (z int) { i := 1 defer func() { z = i + 2 }() return } func main() { fmt.Println(demo()) //3 }
6.3.panic
panic是build中函数,当执行到panic后,终止剩余代码执行,并打印错误栈信息。
//Learn_Go/main.go package main import "fmt" func main() { fmt.Println("111") panic("错误信息") fmt.Println("222") } //结果 111 panic: 错误信息 goroutine 1 [running]: main.main() C:/Users/86158/Desktop/Learn_Go/main.go:8 +0x82
panic不是立即停止程序,defer还是执行的
//Learn_Go/main.go package main import "fmt" func main() { defer fmt.Println("执行defer的内容") fmt.Println("111") panic("错误信息") fmt.Println("222") } //结果 111 执行defer的内容 panic: 错误信息 goroutine 1 [running]: main.main() C:/Users/86158/Desktop/Learn_Go/main.go:9 +0xdc
6.4.recover
recover()表示回复程序的panic(),让程序正常执行
rcover()是和panic一样都是builtin中函数,可以接受panic的信息,恢复程序的正常执行
recover()一般在defer内部,如果没有panic信息,返回nil;如果有panic,recover会把panic状态取消
//Learn_Go/main.go package main import "fmt" func main() { defer func() { if error := recover();error != nil{ fmt.Println("panic为:", error) } }() fmt.Println("111") panic("出现了错误信息") fmt.Println("222") } //结果 111 panic为: 出现了错误信息
函数调用过程中panic和recover()
- recover()只能恢复当前函数级或当前函数调用函数中的panic(),恢复后调用当前级别函数结束,但是调用此函数的函数可以继续执行
- panic会一直向上传递,如果没有recover()则表示程序终止,但是碰见了recover(),recover()所在级别函数表示没有panic,panic就不会向上传递
//Learn_Go/main.go package main import "fmt" func demo1() { fmt.Println("demo1上半部分") demo2() fmt.Println("demo1下半部分") } func demo2() { fmt.Println("demo2上半部分") demo3() fmt.Println("demo2下半部分") } func demo3() { fmt.Println("demo3上半部分") panic("demo3中出现panic") fmt.Println("demo3下半部分") } func main() { fmt.Println("程序开始") demo1() fmt.Println("程序结束") } //结果 程序开始 demo1上半部分 demo2上半部分 demo3上半部分 panic: demo3中出现panic
demo3添加recover()
//Learn_Go/main.go package main import "fmt" func demo1() { fmt.Println("demo1上半部分") demo2() fmt.Println("demo1下半部分") } func demo2() { fmt.Println("demo2上半部分") demo3() fmt.Println("demo2下半部分") } func demo3() { defer func() { recover() }() fmt.Println("demo3上半部分") panic("demo3中出现panic") fmt.Println("demo3下半部分") } func main() { fmt.Println("程序开始") demo1() fmt.Println("程序结束") } //结果 程序开始 demo1上半部分 demo2上半部分 demo3上半部分 demo2下半部分 demo1下半部分 程序结束
demo2添加recover()
//Learn_Go/main.go package main import "fmt" func demo1() { fmt.Println("demo1上半部分") demo2() fmt.Println("demo1下半部分") } func demo2() { defer func() { recover() }() fmt.Println("demo2上半部分") demo3() fmt.Println("demo2下半部分") } func demo3() { fmt.Println("demo3上半部分") panic("demo3中出现panic") fmt.Println("demo3下半部分") } func main() { fmt.Println("程序开始") demo1() fmt.Println("程序结束") } //结果 程序开始 demo1上半部分 demo2上半部分 demo3上半部分 demo1下半部分 程序结束