Google资深工程师深度讲解Go语言-错误处理和资源管理(七)

举报
lxw1844912514 发表于 2022/03/27 00:31:41 2022/03/27
【摘要】 一.defer调用:实现资源管理 确保调用在函数结束时发生参数在defer语句时计算defer列表为后进先出 何时使用defer调用 Open/CloseLock/UnlockPrintHeader/PrintFooter package main import "fmt" func tryDefer(){ defer fmt.Pr...

一.defer调用:实现资源管理

  • 确保调用在函数结束时发生
  • 参数在defer语句时计算
  • defer列表为后进先出

何时使用defer调用

  • Open/Close
  • Lock/Unlock
  • PrintHeader/PrintFooter

  
  1. package main
  2. import "fmt"
  3. func tryDefer(){
  4. defer fmt.Println(1)
  5. defer fmt.Println(2)//defer 相当于栈:先进后出
  6. fmt.Println(3)
  7. //结果:3 2 1
  8. }
  9. func main() {
  10. tryDefer()
  11. }

  
  1. package main
  2. import (
  3. "../../functional/fib"
  4. "bufio"
  5. "fmt"
  6. "os"
  7. )
  8. func tryDefer() {
  9. defer fmt.Println(1)
  10. defer fmt.Println(2) //defer 相当于栈:先进后出
  11. fmt.Println(3)
  12. //结果:3 2 1
  13. //return
  14. panic("error occurred")
  15. fmt.Println(4)
  16. //3
  17. //2
  18. //1
  19. //panic: error occurred
  20. }
  21. //参数在defer语句时计算
  22. func tryDefer2() {
  23. for i := 0; i < 100; i++ {
  24. defer fmt.Println(i) //
  25. if i == 10 {
  26. panic("print too many")
  27. }
  28. }
  29. }
  30. func writeFile(filename string) {
  31. file, err := os.Create(filename)
  32. if err != nil {
  33. panic(err)
  34. }
  35. defer file.Close()
  36. writer := bufio.NewWriter(file)
  37. defer writer.Flush()
  38. f := fib.Fibonacci()
  39. for i := 0; i < 10; i++ {
  40. fmt.Fprintln(writer, f())
  41. }
  42. }
  43. func main() {
  44. //tryDefer()
  45. tryDefer2()
  46. writeFile("fib.txt")
  47. }

二.错误处理理念


  
  1. func writeFile(filename string) {
  2. //file, err := os.Create(filename)
  3. file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE, 0666) //O_EXCL 如果文件存在的话打开不了
  4. // panic: open fib.txt: file exists
  5. err = errors.New("this is a custum error")
  6. if err != nil {
  7. //fmt.Println("Error:",err.Error())
  8. if pathError, ok := err.(*os.PathError); !ok {
  9. panic(err)
  10. } else {
  11. fmt.Printf("%s ,%s ,%s\n ", pathError.Op, pathError.Path, pathError.Err)
  12. }
  13. return
  14. }
  15. defer file.Close()
  16. writer := bufio.NewWriter(file)
  17. defer writer.Flush()
  18. f := fib.Fibonacci()
  19. for i := 0; i < 10; i++ {
  20. fmt.Fprintln(writer, f())
  21. }
  22. }

三.服务器统一出错处理

web.go


  
  1. package main
  2. import (
  3. "./filelisting"
  4. "log"
  5. "net/http"
  6. "os"
  7. )
  8. type appHandler func(writer http.ResponseWriter, request *http.Request) error
  9. //错误包装
  10. func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {
  11. return func(writer http.ResponseWriter, request *http.Request) {
  12. err := handler(writer, request)
  13. if err != nil {
  14. log.Printf("Error handing request:%s",err.Error()) //2020/08/29 17:17:36 Error handing request:open fib2.txt: permission denied
  15. code := http.StatusOK
  16. switch {
  17. case os.IsNotExist(err):
  18. //http.Error(writer, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  19. code = http.StatusNotFound
  20. case os.IsPermission(err):
  21. code = http.StatusForbidden
  22. default:
  23. code = http.StatusInternalServerError
  24. }
  25. http.Error(writer, http.StatusText(code), code)
  26. }
  27. }
  28. }
  29. func main() {
  30. http.HandleFunc("/list/", errWrapper(filelisting.HandleFileList))
  31. err := http.ListenAndServe(":8081", nil)
  32. if err != nil {
  33. panic(err)
  34. }
  35. }

handler.go


  
  1. package filelisting
  2. import (
  3. "io/ioutil"
  4. "net/http"
  5. "os"
  6. )
  7. func HandleFileList(writer http.ResponseWriter, request *http.Request) error {
  8. path := request.URL.Path[len("/list/"):]
  9. file, err := os.Open(path)
  10. if err != nil {
  11. //panic(err)
  12. /*http.Error(writer,
  13. err.Error(),
  14. http.StatusInternalServerError)
  15. return*/
  16. return err
  17. }
  18. defer file.Close()
  19. all, err := ioutil.ReadAll(file)
  20. if err != nil {
  21. //panic(err)
  22. return err
  23. }
  24. writer.Write(all)
  25. return nil
  26. }

四.panic和recover

panin功能作用

  • 停止当前函数执行
  • 一直向上返回,执行每一层的defer
  • 如果没有遇见recover,程序退出

recover功能作用

  • 仅在defer调用中使用
  • 获取panic的值
  • 如果无法处理,可重新panic

  
  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func tryRecover() {
  6. defer func() {
  7. r := recover()
  8. if err, ok := r.(error); ok {
  9. fmt.Println("Error occurred:", err)
  10. } else {
  11. fmt.Println(r)
  12. }
  13. }()
  14. //panic(errors.New("this is an error")) //Error occurred: this is an error,下面不执行,panic停止当前函数执行
  15. b := 0
  16. a := 5 / b
  17. fmt.Println(a) //Error occurred: runtime error: integer divide by zero
  18. }
  19. func main() {
  20. tryRecover()
  21. }

五.服务器统一出错处理

  • 意料之中的:使用error,如文件打不开
  • 意料之外的:使用panic,如数组越界

文章来源: blog.csdn.net,作者:lxw1844912514,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/lxw1844912514/article/details/108291996

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。