• Go语言学习日记【三十二】golang代码错误处理【error,defer,recover】


    前言:

            代码异常处理是学习任何编程语言都需要考虑的一个重要话题。比如C++,python都引入exception的概念和try_catch  try_except的引入。golang自然也有自己独特的异常处理方式。漂亮的异常处理方式也是golang语言最大的亮点之一,下面重点解析一下golang错误处理方式。

    一、error接口

           Go语言引入了一个关于错误处理的标准模式,即 error 接口,该接口的定义如下:

    1. type error interface {
    2. Error() string
    3. }

             在golang代码中,对于大多数函数,如果要返回错误,大致上都可以定义为如下模式

    1. func myFunc(param string)(str string, err error) {
    2. // ...
    3. }

             将 error 作为多种返回值中的最后一个,但这并非是强制要求

             调用时的代码建议按如下方式处理错误情况        

    1. _, err := myTest("test")
    2. if err != nil {
    3. // 错误处理
    4. } else {
    5. // ......
    6. }

            同时,在代码中,我们可以自定义error类型,举例如下

    1. type DefineError struct {
    2. Define string
    3. Err error
    4. }
    5. // 定义Error函数
    6. func (d *DefineError) Error() string {
    7. return d.Define + d.Err.Error()
    8. }

           这样,当函数调用失败返回 err 时,将该 err 包装到一个 DefineError 对象中返回

    1. func Stat() (err error) {
    2. err = myFunc()
    3. if err != nil {
    4. return nil, &DefineError{"define", err}
    5. }
    6. // ......
    7. }

    二、defer

            在函数编写过程中,有时引入异常会导致代码异常退出,但是,之前打开的诸如文件句柄这些操作如果不关闭,会导致程序在运行过程中出现问题。而在golang语言中,通过defer关键字轻轻松松的解决了这个问题。

            代码示例:

    1. package main
    2. import "fmt"
    3. func main() {
    4. defer fmt.Println("main defer:1")
    5. defer fmt.Println("main defer:2")
    6. fmt.Println("main --:1")
    7. panic("--- error ---")
    8. fmt.Println("main --:2")
    9. defer fmt.Println("main defer:5")
    10. defer fmt.Println("main defer:6")
    11. }
    12. /*
    13. main --:1
    14. main defer:2
    15. main defer:1
    16. panic: --- error ---
    17. goroutine 1 [running]:
    18. main.main()
    19. */

            通过代码测试可以看出,当程序出现异常时,程序异常部分下面的代码将不再执行,而异常上面部分的defer代码,将在异常抛出后逆序执行。因此,当我们把要执行的句柄操作通过defer放在函数起始位置,无论程序执行是否异常,句柄关闭操作都能在程序里安全执行。

    三、panic与recover

            panic:在函数中如果书写并触发了panic语句,会终止其后要执行的代码。在panic所在函数内如果存在要执行的defer函数列表,则按照defer书写顺序的逆序执行,同时,如果该函数被其他函数调用,则调用函数在调用代码后面的代码都不会执行,如果存在defer语句,一样逆序执行。在代码最后,则抛出panic异常。代码示例:

    1. package main
    2. import "fmt"
    3. func main() {
    4. defer fmt.Println("main defer:1")
    5. defer fmt.Println("main defer:2")
    6. fmt.Println("main --:1")
    7. myTest()
    8. fmt.Println("main --:2")
    9. defer fmt.Println("main defer:5")
    10. defer fmt.Println("main defer:6")
    11. }
    12. func myTest() {
    13. defer fmt.Println("myTest defer:1")
    14. defer fmt.Println("myTest defer:2")
    15. fmt.Println("myTest --:1")
    16. panic("manaual error")
    17. defer fmt.Println("myTest defer:4")
    18. defer fmt.Println("myTest defer:5")
    19. }
    20. /*
    21. main --:1
    22. myTest --:1
    23. myTest defer:2
    24. myTest defer:1
    25. main defer:2
    26. main defer:1
    27. panic: manaual error
    28. goroutine 1 [running]:
    29. main.myTest()
    30. D:/code/go/go/01-错误演示.go:19 +0x165
    31. main.main()
    32. D:/code/go/go/01-错误演示.go:9 +0x173
    33. Process finished with exit code 2
    34. */

          recover:

    1. recover的作用是捕获panic,从而恢复正常代码执行;
    2. recover必须配合defer使用;
    3. recover没有传入参数,但是有返回值,返回值就是panic传递的值

         代码示例:

    1. package main
    2. import "fmt"
    3. func main() {
    4. defer fmt.Println("main defer:1")
    5. defer fmt.Println("main defer:2")
    6. fmt.Println("main --:3")
    7. myTest()
    8. fmt.Println("main --:4")
    9. defer fmt.Println("main defer:5")
    10. defer fmt.Println("main defer:6")
    11. }
    12. func myTest() {
    13. defer fmt.Println("---------------")
    14. defer func() {
    15. if msg := recover(); msg != nil {
    16. fmt.Println("panic信息:", msg, "---recover恢复---")
    17. }
    18. }()
    19. defer fmt.Println("myTest defer:1")
    20. defer fmt.Println("myTest defer:2")
    21. fmt.Println("myTest --:1")
    22. panic("manaual error")
    23. defer fmt.Println("myTest defer:4")
    24. defer fmt.Println("myTest defer:5")
    25. }
    26. /*
    27. Process finished with exit code 0
    28. */

  • 相关阅读:
    开发技术-Java定位并打印异常信息
    Trie字典树
    Rust ?运算符 Rust读写txt文件
    HTML入门零基础教程(五)
    【无标题】
    Qt发布exe软件及修改exe应用程序图标
    vite+react+typescript 遇到的问题
    Qlik Sense Websocket Connectivity Tester
    Go-Excelize API源码阅读(三十九)——SetCellHyperLink
    少儿编程 | 探讨C++课程、MIT Scratch课程、python课程、Noi竞赛、蓝桥怎么引导?如何才能让小孩子飞的更高?附开发工具的下载与安装
  • 原文地址:https://blog.csdn.net/qq_41982304/article/details/126720273