defer的调用
确保调用在函数结束的时候发生
参数在defer语句时计算
defer列表为后进先出
func writeFile(filename string) {
file, err := os.Create(filename)
if err != nil {
panic(err)
}
defer file.Close() //确保在函数结束的时候关闭文件
//直接用file写比较慢,使用bufio,先写到内存里,当内容大到一定的程度之后,再写到文件中
writer := bufio.NewWriter(file)
defer writer.Flush() //缓冲-->文件
f := fib.Fibonacci()
for i := 0; i < 20; i++ {
fmt.Fprintln(writer, f())
}
}
错误处理
error其实就是一个接口
func writeFileError(filename string) {
file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE, 0666) //如果存在文件,打开不了
//err = errors.New("This is custom error") //自定义error
if err != nil {
//将error转为我们已知的错误类型
if pathError, ok := err.(*os.PathError); !ok { //判断*os.PathError是否实现error接口
panic(err)
} else {
fmt.Println(pathError.Op, " ", pathError.Path, " ", pathError.Err.Error())
}
return
}
defer file.Close() //确保在函数结束的时候关闭文件
//直接用file写比较慢,使用bufio,先写到内存里,当内容大到一定的程度之后,再写到文件中
writer := bufio.NewWriter(file)
defer writer.Flush() //缓冲-->文件
f := fib.Fibonacci()
for i := 0; i < 20; i++ {
fmt.Fprintln(writer, f())
}
}
如何实现统一的错误逻辑?
panic和recover
panic
- 停止当前函数的执行。
- 一直向上返回,执行每一层的defer。
- 如果没有遇到recover,程序退出。
recover
- 仅在defer调用中使用。
- 获取panic的值。
- 如果无法处理,可以重新panic。
panic和recover的参数类型都是interface{}。
func panic(v interface{})
func recover() interface{}
func tryRecover() {
defer func() {
r := recover()
if err, ok := r.(error); ok { //r.(error) 将interface{}转为具体的类型
fmt.Println("Error occured: ", err)
} else {
panic(
fmt.Sprintf("I don't know what to do: %v", r),
)
}
}()
//panic(errors.New("This is an error"))
b := 0
a := 5 / b
fmt.Println(a)
//panic(123)
}
func main() {
tryRecover()
}
有两种错误信息,一种可以给用户看到的错误信息,一种的error错误在代码中将其以log.Warn()的形式出现。输出的错误信息一般都使用小写。
意料之中的使用error,如文件打不开。 意料之外的使用panic,如数组越界。
实例:简单Web服务器,输入相应URL,显示文件内容,可以处理路径错误等错误信息。