Defer, Panic, and Recover[翻译]
Go语言提供一般的流程控制语句: 一个 让我们演示一个文件复制的例子: 函数需要打开两个文件,然后将其中一个文件的内容复制到另一个文件: func CopyFile(dstName,srcName string) (written int64,err error) { src,err := os.Open(srcName) if err != nil { return } dst,err := os.Create(dstName) if err != nil { return } written,err = io.Copy(dst,src) dst.Close() src.Close() return } 上面的代码虽然能够工作,但是隐藏一个bug. 如果第二个 func CopyFile(dstName,err := os.Open(srcName) if err != nil { return } defer src.Close() dst,err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst,src) } Defer语言可以让我们在打开文件时就思考如何关闭文件. 不管函数如何返回,文件关闭语句始终会被执行. Defer语句的行为简单且可预测. 有三个基本原则: 1. 当defer调用函数的时候,函数用到的每个参数和变量的值也会被计算 在这个例子中,表达式 func a() { i := 0 defer fmt.Println(i) i++ return } 2. Defer调用的函数将在当前函数返回的时候,以后进先出的顺序执行. 下面的函数将输出 func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } } 3. Defer调用的函数可以在返回语句执行后读取或修改命名的返回值. 在这个例子中, func c() (i int) { defer func() { i++ }() return 1 } 利用该特性,我们可以方便修改函数的错误返回值. 以后应该可以看到类似的例子.
下面的例子演示了 package main import "fmt" func main() { f() fmt.Println("Returned normally from f.") } func f() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f",r) } }() fmt.Println("Calling g.") g(0) fmt.Println("Returned normally from g.") } func g(i int) { if i > 3 { fmt.Println("Panicking!") panic(fmt.Sprintf("%v",i)) } defer fmt.Println("Defer in g",i) fmt.Println("Printing in g",i) g(i + 1) } 函数 程序的输出: Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f. 如果我们从函数 Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 panic: 4 panic PC=0x2a9cd8 [stack trace omitted] 一个真实的 Go库的实现习惯: 即使在 另一个使用 mu.Lock() defer mu.Unlock() 打印页眉和页脚: printHeader() defer printFooter() 更多. 总而言之, (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |