1. 拦截 panic
// $GOROOT/src/bytes/buffer.go
func makeSlice(n int) []byte {
// If the make fails, give a known error.
defer func() {
if recover() != nil {
panic(ErrTooLarge) // 触发一个新panic
}
}()
return make([]byte, n)
}
defer function 中是用 recover
是 Golang 中唯一从 panic
中恢复的手段,能够拦截运行时中的 panic
,但是对运行时之外触发的崩溃无法捕获,比如调用 C 语言的库,C 语言中发生的崩溃。
2. 修改函数的具名返回值
下面是一个标准库中的例子:
// $GOROOT/src/fmt/scan.go
func (s *ss) Token(skipSpace bool, f func(rune) bool) (tok []byte, err error) {
defer func() {
if e := recover(); e != nil {
if se, ok := e.(scanError); ok {
err = se.err
} else {
panic(e)
}
}
}()
...
}
3. 输出调试信息
下面这个例子通过 defer
给函数加上了调用和退出的调试日志。
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
4. 还原变量旧值
下面同样是一个来自标准库的例子:
// $GOROOT/src/syscall/fs_nacl.go
func init() {
oldFsinit := fsinit
defer func() { fsinit = oldFsinit }()
fsinit = func() {}
Mkdir("/dev", 0555)
Mkdir("/tmp", 0777)
mkdev("/dev/null", 0666, openNull)
mkdev("/dev/random", 0444, openRandom)
mkdev("/dev/urandom", 0444, openRandom)
mkdev("/dev/zero", 0666, openZero)
chdirEnv()
}