1、error接口
Go语言引入了一个关于错误处理的标准模式,即error接口,该接口的定义如下:
1 2 3 4 |
type error interface { Error() string } |
对于大多数函数,如果需要返回错误,大致可以定义如下模式,将error
作为多返回值中的最后一个即可,但是这并非是强制要求:
1 2 3 4 |
func Foo(i int) (n int, err error) { // ... } |
需要时,可以如下调用:
1 2 |
n, err := Foo(0) |
下面使用Go库中的实际代码来示范如何自定义error
类型。
1 2 3 4 5 6 7 8 9 10 |
type PathError struct { Op string Path string Err error } func (e *PathError) Error() string { return e.Op + " " + e.Path + " " + e.Err.Error() } |
调用可以如下:
1 2 3 4 5 6 |
err = syscall.Stat(name, &stat) if err != nil { return nil, &PathError{"stat", name, err} } |
2、defer
关键字defer
允许我们推迟到函数返回之前(或任意位置执行 return
语句之后)一刻才执行某个语句或函数(为什么要在返回之后才执行这些语句?因为 return
语句同样可以包含一些操作,而不是单纯地返回某个值)。
关键字 defer 的用法类似于面向对象编程语言 Java
和 C#
的 finally
语句块,它一般用于释放某些已分配的资源。
下面的例子可以简单的解释defer
的用法,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
func CopyFile(dst, src string) (w int64, err error) { srcFile, err := os.Open(src) if err != nil { return } defer srcFile.Close() dstFile, err := os.Create(dst) if err != nil { return } defer dstFile.Close() return io.Copy(dstFile, srcFile) } |
如果一句话干不完清理的工作,可以使用在defer
后加一个匿名函数的做法:
1 2 3 4 |
defer func() { // ... }() |
另外,一个函数里可以存在多个defer
,因此需要注意的是,defer
语句遵循先进后出的原则,即最后一个defer
第一个执行,第一个defer
最后一个执行。
3、panic
和recover
Go语言引入了两个内置函数panic()
和recover()
,用以报告和处理运行时错误和程序中的错误场景:
1 2 3 |
func panic(interface{}) func recover() interface{} |
使用方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<br />func main() { fmt.Println("a") a() fmt.Println("b") } func a() { fmt.Println(1) fmt.Println(2) b() fmt.Println(3) } func b() { defer func() { if r := recover(); r != nil { fmt.Println(r) } }() fmt.Println("11") panic("Error") fmt.Println("12") } |