Google资深工程师深度讲解Go语言-错误处理和资源管理(七)
        【摘要】 
                    一.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)