ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

Go语言第九章(错误处理)

Go语言第九章(错误处理) 错误处理Go没有try / catch。日常约定是能预期的失败参数不对、查无此人、除数为 0→ 返回error由调用方决定怎么处理。不该发生、程序状态已不可信下标越界、断言失败、严重逻辑崩坏→ 用panic必要时再在上层用deferrecover兜底。本文用「九九乘法表」同一个业务场景对比这两种写法的差别。业务错误 vs 程序错误类型常见手段出错后同函数里后面的代码典型场景业务错误返回(结果, error)还能继续走只要你没return用户输入非法、业务校验失败程序错误panic不再执行即使recover了也是如此严重异常、不可恢复状态记住口诀业务错误是「报告给调用方」程序错误是「当前这条执行路径断了」。业务错误返回errorerror是内置接口只有一个方法Error() string。没出错返回nil有错返回非nil。下面要求参数必须是9才打印九九表传8时返回错误。注意处理完错误之后main里的「其余逻辑」仍然会执行。packagemainimport(errorsfmt)// 业务校验失败返回 error不中断整个程序funcnn(aint)(bool,error){ifa!9{returnfalse,errors.New(请输入9)}fori:1;ia;i{fork:1;ki;k{fmt.Printf(%d * %d %d ,k,i,i*k)}fmt.Println()}returntrue,nil}funcmain(){success,err:nn(8)iferr!nil{fmt.Println(err,执行失败)}else{fmt.Println(success,执行成功)}// 业务错误只是「这次调用失败」后面的代码照常走fmt.Println(其余逻辑)}输出类似请输入9 执行失败 其余逻辑要点用errors.New(说明)或fmt.Errorf(a%d 非法, a)创建错误。调用方标准姿势if err ! nil { ... }。返回错误后函数正常结束调用方可以打日志、换参数重试也可以继续干别的事。程序错误panic把「请输入 9」改成panic。一旦触发从panic那一行开始同函数里后面的代码不会再跑。先看没有recover的情况——进程会直接崩溃packagemainimportfmtfuncnn(aint)(bool,error){ifa!9{panic(请输入9)// 程序错误直接中断当前执行路径}fori:1;ia;i{fork:1;ki;k{fmt.Printf(%d * %d %d ,k,i,i*k)}fmt.Println()}returntrue,nil}funcmain(){success,err:nn(8)iferr!nil{fmt.Println(err,执行失败)}else{fmt.Println(success,执行成功)}// 上面已经 panic这行永远走不到fmt.Println(其余逻辑)}运行后会看到 panic 栈且没有「其余逻辑」。这就是和业务错误最大的差别。defer 用法defer会把一次函数调用推迟到当前函数即将返回之前执行常用于关文件、解锁、以及配合recover捕获panic。基本顺序先写正常逻辑defer的内容最后跑。packagemainimportfmtfuncmain(){fmt.Println(开始)deferfmt.Println(defer收尾)fmt.Println(业务逻辑)}输出开始 业务逻辑 defer收尾多个defer按后进先出LIFO执行——最后注册的最先跑packagemainimportfmtfuncmain(){deferfmt.Println(第一)deferfmt.Println(第二)deferfmt.Println(第三)fmt.Println(函数体)}输出函数体 第三 第二 第一和错误处理相关的关键点recover必须写在defer里才有效普通代码里调用recover()拿不到 panic。defer常用来保证「出错也要收尾」关文件、释放锁、打印现场。参数在写defer那一刻就算好不是真正执行时才算。更多细节见「Go 函数」一文的 defer 小节。用deferrecover兜住 panic加上recover后进程不会崩溃可以打印 panic 信息但panic发生点之后的代码仍然不会执行。packagemainimportfmtfuncnn(aint)(bool,error){ifa!9{panic(请输入9)}fori:1;ia;i{fork:1;ki;k{fmt.Printf(%d * %d %d ,k,i,i*k)}fmt.Println()}returntrue,nil}funcmain(){deferfunc(){ifinfo:recover();info!nil{fmt.Println(捕获到程序错误:,info)}}()success,err:nn(8)// 这里 paniciferr!nil{fmt.Println(err,执行失败)}else{fmt.Println(success,执行成功)}// panic 之后同函数里这些代码依然不走fmt.Println(其余逻辑)}输出类似捕获到程序错误: 请输入9没有「执行失败 / 执行成功」也没有「其余逻辑」。recover的作用是拦住崩溃不是从 panic 下一行接着跑。怎么选情况建议用户输错、查不到数据、权限不够返回error库函数约定用error如os.Open跟着返回 / 包装error明显的编程错误、不可继续的状态可以panic服务入口想避免整个进程挂掉边界处deferrecover打日志后返回错误响应入门阶段优先练好if err ! nilpanic/recover留给真正的异常路径不要拿来代替普通业务校验。作业返回 error写divide(a, b int) (int, error)b 0时返回错误否则返回商。在main里分别用(10, 2)和(10, 0)调用并处理。业务错误对比改写文中的nn允许传入19任意整数打印对应乘法表小于1或大于9时返回error。调用失败后打印一句「其余逻辑」确认它仍会执行。defer 顺序在main里注册三个defer打印A、B、C再打印一句「函数体」观察输出顺序是否为「函数体 → C → B → A」。panic 与 recover写一个函数mustPositive(n int)n 0时panic。在main里用deferrecover捕获打印 panic 信息并在调用后面再写一句fmt.Println(其余逻辑)验证它不会执行。综合练习写printTable(n int) error业务错误版和mustPrintTable(n int)n ! 9就panic。在main里先演示返回error后后续代码仍运行再用recover演示panic被兜住但后续代码不运行。
返回列表