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

举报
lxw1844912514 发表于 2022/03/27 00:31:41 2022/03/27
1.2k+ 0 0
【摘要】 一.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

      package main
      import "fmt"
      func tryDefer(){
     	defer fmt.Println(1)
     	defer fmt.Println(2)//defer 相当于栈:先进后出
      	fmt.Println(3)
     	//结果:3 2 1
      }
      func main() {
      	tryDefer()
      }
  
 

      package main
      import (
     	"../../functional/fib"
     	"bufio"
     	"fmt"
     	"os"
      )
      func tryDefer() {
     	defer fmt.Println(1)
     	defer fmt.Println(2) //defer 相当于栈:先进后出
      	fmt.Println(3)
     	//结果:3 2 1
     	//return
     	panic("error occurred")
      	fmt.Println(4)
     	//3
     	//2
     	//1
     	//panic: error occurred
      }
      //参数在defer语句时计算
      func tryDefer2() {
     	for i := 0; i < 100; i++ {
     		defer fmt.Println(i) //
     		if i == 10 {
     			panic("print too many")
      		}
      	}
      }
      func writeFile(filename string) {
      	file, err := os.Create(filename)
     	if err != nil {
     		panic(err)
      	}
     	defer file.Close()
      	writer := bufio.NewWriter(file)
     	defer writer.Flush()
      	f := fib.Fibonacci()
     	for i := 0; i < 10; i++ {
      		fmt.Fprintln(writer, f())
      	}
      }
      func main() {
     	//tryDefer()
      	tryDefer2()
      	writeFile("fib.txt")
      }
  
 

二.错误处理理念


      func writeFile(filename string) {
     	//file, err := os.Create(filename)
      	file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE, 0666) //O_EXCL 如果文件存在的话打开不了
     	// panic: open fib.txt: file exists
      	err = errors.New("this is a custum error")
     	if err != nil {
     		//fmt.Println("Error:",err.Error())
     		if pathError, ok := err.(*os.PathError); !ok {
     			panic(err)
      		} else {
      			fmt.Printf("%s ,%s ,%s\n ", pathError.Op, pathError.Path, pathError.Err)
      		}
     		return
      	}
     	defer file.Close()
      	writer := bufio.NewWriter(file)
     	defer writer.Flush()
      	f := fib.Fibonacci()
     	for i := 0; i < 10; i++ {
      		fmt.Fprintln(writer, f())
      	}
      }
  
 

三.服务器统一出错处理

web.go


      package main
      import (
     	"./filelisting"
     	"log"
     	"net/http"
     	"os"
      )
      type appHandler func(writer http.ResponseWriter, request *http.Request) error
      //错误包装
      func errWrapper(handler appHandler) func(http.ResponseWriter, *http.Request) {
     	return func(writer http.ResponseWriter, request *http.Request) {
      		err := handler(writer, request)
     		if err != nil {
      			log.Printf("Error handing request:%s",err.Error()) //2020/08/29 17:17:36 Error handing request:open fib2.txt: permission denied
      			code := http.StatusOK
     			switch {
     			case os.IsNotExist(err):
     				//http.Error(writer, http.StatusText(http.StatusNotFound), http.StatusNotFound)
      				code = http.StatusNotFound
     			case os.IsPermission(err):
      				code = http.StatusForbidden
     			default:
      				code = http.StatusInternalServerError
      			}
      			http.Error(writer, http.StatusText(code), code)
      		}
      	}
      }
      func main() {
      	http.HandleFunc("/list/", errWrapper(filelisting.HandleFileList))
      	err := http.ListenAndServe(":8081", nil)
     	if err != nil {
     		panic(err)
      	}
      }
  
 

handler.go


      package filelisting
      import (
     	"io/ioutil"
     	"net/http"
     	"os"
      )
      func HandleFileList(writer http.ResponseWriter, request *http.Request) error {
      	path := request.URL.Path[len("/list/"):]
      	file, err := os.Open(path)
     	if err != nil {
     		//panic(err)
     		/*http.Error(writer,
       err.Error(),
       http.StatusInternalServerError)
       return*/
     		return err
      	}
     	defer file.Close()
      	all, err := ioutil.ReadAll(file)
     	if err != nil {
     		//panic(err)
     		return err
      	}
      	writer.Write(all)
     	return nil
      }
  
 

四.panic和recover

panin功能作用

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

recover功能作用

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

      package main
      import (
     	"fmt"
      )
      func tryRecover() {
     	defer func() {
      		r := recover()
     		if err, ok := r.(error); ok {
      			fmt.Println("Error occurred:", err)
      		} else {
      			fmt.Println(r)
      		}
      	}()
     	//panic(errors.New("this is an error")) //Error occurred: this is an error,下面不执行,panic停止当前函数执行
      	b := 0
      	a := 5 / b
      	fmt.Println(a) //Error occurred: runtime error: integer divide by zero
      }
      func main() {
      	tryRecover()
      }
  
 

五.服务器统一出错处理

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

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

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

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

作者其他文章

评论(0

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

    全部回复

    上滑加载中

    设置昵称

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

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

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