Defer
调用特点
-
确保调用在函数结束时发生
-
defer列表为后进先出,参数在defer语句时才计算
func tryDefer() { defer fmt.Println(1) defer fmt.Println(2) fmt.Println(3) //return panic("error occurred") fmt.Println(4) } --------- 3 2 1
常见使用defer调用场景
- Open/Close
- Lock/Unlock
- PrintHeader/PrintFooter
错误处理
-
常用错误处理
file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666) if err != nil { 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()
-
服务器统一错误处理
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) { // panic defer func() { if r := recover(); r != nil { log.Printf("Panic: %v", r) http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } }() err := handler(writer, request) if err != nil { log.Printf("Error occurred "+ "handling request: %s", err.Error()) // user error if userErr, ok := err.(userError); ok { http.Error(writer, userErr.Message(), http.StatusBadRequest) return } // system error code := http.StatusOK switch { case os.IsNotExist(err): code = http.StatusNotFound case os.IsPermission(err): code = http.StatusForbidden default: code = http.StatusInternalServerError } http.Error(writer, http.StatusText(code), code) } } } type userError interface { error Message() string }
Panic
- 停止当前函数执行
- 一直向上返回,执行每一层的defer
- 如果没有遇见recover,程序退出
Recover
-
仅在defer调用中使用
-
获取panic的值
-
如果无法处理,可以重新panic
func tryRecover() { defer func() { r := recover() if r == nil { fmt.Println("Nothing to recover. " + "Please try uncomment errors " + "below.") return } if err, ok := r.(error); ok { fmt.Println("Error occurred:", err) } else { panic(fmt.Sprintf( "I don't know what to do: %v", r)) } }() // Uncomment each block to see different panic // scenarios. // Normal error //panic(errors.New("this is an error")) // Division by zero //b := 0 //a := 5 / b //fmt.Println(a) // Causes re-panic //panic(123) }
Error vs Panic
- 意料之中的使用error,如:文件打不开等
- 意料之外的使用panic,如:数组越界