文章目录
0 前言
合理,成对使用
1、资源管理与出错处理
1.1 defer调用
- go语言是通过defer调用来实现资源管理的
- 确保调用在函数结束时候发生
简单例子1
package main
import "fmt"
func tryDefer(){
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
//return
panic("error occurred")
fmt.Println(4)
}
func main(){
tryDefer()
}
//return
3
2
1
panic: error occurred
goroutine 1 [running]:
main.tryDefer()
/Users/*******/GolandProjects/gotest/src/defer/defer.go:10 +0x165
main.main()
/Users/*******/GolandProjects/gotest/src/defer/defer.go:15 +0x25
Process finished with exit code 2
defer的运行顺序是这个样子的:
- 不运行tryDefer函数中的defer语句,运行完毕函数
- 然后按照栈的性质一次运行defer语句
- 中间有return或者panic都不会影响defer语句的运行
简单例子2
package main
import (
"bufio"
"fmt"
"os"
)
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 := fibonacci()
for i := 0; i < 20; i++{
fmt.Fprintln(writer, f())
}
}
func main(){
writeFile("src/abc.txt")
}
2、出错处理概念
func writeFile(filename string){
file, err := os.OpenFile(
filename, os.O_EXCL|os.O_CREATE, 0666)
if err != nil{
if pathError, ok := err.(*os.PathError); !ok {
panic(err)
}else{
fmt.Println(pathError.Op,
pathError.Path,
pathError.Err)
}
return
}
if err != nil{
panic(err)
}
defer file.Close()
writer := bufio.NewWriter(file)
defer writer.Flush()
f := fibonacci()
for i := 0; i < 20; i++{
fmt.Fprintln(writer, f())
}
}
2.1 自定义error
func writeFile(filename string){
file, err := os.OpenFile(
filename, os.O_EXCL|os.O_CREATE, 0666)
err = errors.New("this is a custom error")
if err != nil{
if pathError, ok := err.(*os.PathError); !ok {
panic(err)
}else{
fmt.Println(pathError.Op,
pathError.Path,
pathError.Err)
}
return
}
if err != nil{
panic(err)
}
defer file.Close()
writer := bufio.NewWriter(file)
defer writer.Flush()
f := fibonacci()
for i := 0; i < 20; i++{
fmt.Fprintln(writer, f())
}
}
3、服务器统一出错处理
3.1 实现统一的错误处理逻辑
将错误的代码放到一个函数中
// main.go
package main
import (
"filelistingserver/filelisting"
"github.com/gpmgo/gopm/modules/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.Warn("Error handling request : %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(":8888", nil)
if err != nil{
panic(err)
}
}
// filelist.go
package filelisting
import (
"io/ioutil"
"net/http"
"os"
)
func HandlefileList(writer http.ResponseWriter, request *http.Request) error{
path := request.URL.Path[len("/list/"): ] // /list/fib.txt
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
}
4、panic和recover
4.1 panic
- 停止当前函数执行
- 一直向上返回,执行每一层的defer
- 如果没有遇见recover,程序退出
4.2 recover
- 仅在defer中调用
- 获取panic值
- 如果无法获取处理,可重新panic
package main
import (
"fmt"
)
func tryRecover(){
defer func() {
r := recover()
if err, ok := r.(error); ok{
fmt.Println("Error occured: ", err)
}else{
panic(r)
}
}()
// panic(errors.New("this is an error"))
//b := 0
//a := 5 / b
//fmt.Println(a)
// 此时如果报一个123的错误,recover不知道这是啥,所以就没有办法去处理,所以会panic出来
panic(123)
}
func main() {
tryRecover()
}