恢复#
延迟函数调用
如果你有一个无论如何希望确保运行的函数调用,都可以使用defer语句。你可以将defer关键字放在任何普通函数或方法调用之前,Go将延迟(也就是推迟)执行函数调用,直到当前函数退出之后。
defer语句是Go中一个非常有用的特性,可以将一个方法延迟到包裹该方法的方法返回时执行,在实际应用中,defer语句可以充当其他语言中try…catch…的角色,也可以用来处理关闭文件句柄等收尾操作。
package main type name interface { } func main() { defer func() { println("close main") }() f := func(i1 int) { println(i1) } { defer func() { println("close close") }() f(11) } f(10) }
- “defer”关键字确保函数调用发生,即使调用函数提前退出了。
列出目录中的文件
io/ioutil包包含一个ReadDir函数,它允许我们读取目录内容。向ReadDir传递一个目录的名称,它将返回一个值切片,每个值切片对应目录包含的每个文件或子目录(以及遇到的任何错误)。
每个切片的值都满足FileInfo接口,该接口包括一个返回文件名的Name方法和一个如果是目录则返回true的IsDir方法。
递归函数调用
package main import ( "errors" "io/ioutil" "path/filepath" ) func readDir(path string,i int) error { dir, err := ioutil.ReadDir(path) if err!=nil { for ti:=0;ti<i;ti++ { print(" ") } println(path) }else { for _,info := range dir { join := filepath.Join(path, info.Name()) if info.IsDir() { for ti:=0;ti<i;ti++ { print(" ") } println(path,"{") err := readDir(join, i+1) if err!=nil { return errors.New(join+" err") } for ti:=0;ti<i;ti++ { print(" ") } println("}") }else { for ti:=0;ti<i;ti++ { print(" ") } println(join) } } } return nil } func main() { err := readDir("./", 1) if err != nil { print("ERR") } }

panic
当程序出现panic时,当前函数停止运行,程序打印日志消息并崩溃。
可以通过简单地调用内置的panic函数来引发panic。
package main func main() { panic("err") println("hello") }
- panic函数需要一个满足空接口的参数(也就是说,它可以是任何类型)。该参数将被转换为字符串(如果需要),并作为panic日志信息的一部分打印出来。
堆栈跟踪
每个被调用的函数都需要返回到调用它的函数。为了实现这一点,就像其他编程语言一样,Go保持一个调用堆栈,即在任何给定点上处于活动状态的函数调用的列表。当程序发生panic时,panic输出中包含堆栈跟踪,即调用堆栈列表。这对于确定导致程序崩溃的原因很有用。
package main func f1() { println("1") f2() } func f2() { println("2") f3() } func f3() { println("3") f4() } func f4() { println("4") f5() } func f5() { panic("ERR") println("5") } func main() { f1() }
延迟调用在崩溃前完成
当程序出现panic时,所有延迟的函数调用仍然会被执行。如果有多个延迟调用,它们的执行顺序将与被延迟的顺序相反。
package main func f1() { println("1") f2() } func f2() { defer println("defer 2") println("2") f3() } func f3() { defer println("defer 3") println("3") f4() } func f4() { defer println("defer 4") println("4") f5() } func f5() { defer println("defer 5") panic("ERR") println("5") } func main() { f1() }
- panic 在 defer之后打印。
“recover”函数
Go提供了一个内置的recover函数,可以阻止程序陷入panic。我们需要使用它来体面地退出程序。
在正常程序执行过程中调用recover时,它只返回nil,而不执行其他操作
func main() { println(recover()==nil) }
如果在程序处于panic状态时调用recover,它将停止panic。但是当你在函数中调用panic时,该函数将停止执行。因此,在panic所在的同一函数中调用recover没有意义,因为panic无论如何都会继续:
但是,当程序陷入panic时,有一种方法可以调用recover……在panic期间,任何延迟的函数调用都将完成。因此,可以在一个单独的函数中放置一个recover调用,并在引发panic的代码之前使用defer调用该函数。
调用recover不会导致在出现panic时恢复执行,至少不会完全恢复。产生panic的函数将立即返回,而该函数块中panic之后的任何代码都不会执行。但是,在产生panic的函数返回之后,正常的执行将恢复。
package main func f1() { println("1") f2() } func f2() { defer println("defer 2") println("2") f3() println("Hello f2 end") } func f3() { defer func() { if r := recover(); r != nil { println("recover err") } }() println("3") f4() } func f4() { defer println("defer 4") println("4") f5() } func f5() { defer println("defer 5") panic("ERR") println("5") } func main() { f1() println("Hello") }
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!





