defer 调用
确保调用在函数结束时发生,从下面的例子我们可以发现,defer的列表为先进后出
// 3
// 2
// 1
// panic: error
func tryDefer() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
panic("error")
fmt.Println(4)
}
参数在defer语句时进行计算
// 3
// 2
// 1
func tryDefer() {
for i := 0; i < 10; i++ {
defer fmt.Println(i)
if(i == 3) {
panic("printed too many")
}
}
}
错误统一处理
下面以一个http web server 的例子来叙述如何对错误进行统一处理
package main
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.Warn("error %s", err.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)
}
}
}
func main() {
http.HandleFunc("/list/", errWrapper(filelisting.HandleFileList))
err := http.ListenAndServe(":12345", nil)
if err != nil {
panic(err)
}
}
package filelisting
func HandleFileList(writer http.ResponseWriter, request *http.Request) error {
path := request.URL.Path[len("/list/"):]
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
all, err := ioutil.ReadAll(file)
if err != nil {
return err
}
writer.Write(all)
return nil
}
panic
- 停止当前函数执行
- 一直向上返回,执行每一层的defer
- 如果没有遇见revocer,程序退出
revocer
- 仅在defer 调用中使用
- 获取panic 的值
- 如果无法处理可重新panic
revocer 的使用
func tryRecover() {
defer func() {
r := recover()
if err, ok := r.(error); ok {
fmt.Println("Error occurred: ", err)
} else {
panic(fmt.Sprintf("I dont know that to do: %v", r))
}
}()
panic(errors.New("this is an error"))
}
func main() {
tryRecover()
}