标签:recover 需要 流程 参数 文件流 puts UNC open 关闭数据库
关键字defer
允许推迟到函数返回之前(或任意位置执行return
语句后)才执行某个语句或者函数。return
语句同样可以包含一些操作,所以可能存在将语句推迟到return
之后的需求。关键字defer
的用法类似于面向对象编程语言Java和C#的finally
语句块,一般用于释放某些已分配的资源。
Go中,defer
担任try catch
的工作,需要给予充分注意。
延时调用函数的语法:
defer func_name(param_list)
当一个函数调用前有关键字defer
时,这个函数的执行会推迟到包含这个defer
语句的函数即将返回前才执行,例如:
package main
import "fmt"
func main() {
function1()
}
func function1() {
fmt.Printf("In function1 at the top\n")
defer function2()
fmt.Printf("In function1 at the bottom\n")
}
func function2() {
fmt.Printf("Function2: Deferred until the end of the calling function")
}
其输出结果为:
In function1 at the top
In function1 at the bottom
Function2: Deferred until the end of the calling function
如果有多个defer
调用,则其调用顺序为先进后出,类似于栈。
package main
import "fmt"
func f() (r int) {
defer func() {
r++
}()
return 0
}
func main() {
fmt.Println(f())
}
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
inputFile, inputError := os.Open("input.dat")
if inputError != nil {
fmt.Printf("An error occurred on opening the inputfile\n" +
"Does the file exists?\n" +
"Have you got access to it?\n")
return // exit the function on error
}
defer inputFile.Close()
inputReader := bufio.NewReader(inputFile)
for {
inputString, readerError := inputReader.ReadString(‘\n‘)
fmt.Printf("The input was: %s", inputString)
if readerError == io.EOF {
return
}
}
}
mu.Lock()
defer mu.Unlock()
printHeader()
defer printFooter()
defer disconnectFromDB()
合理使用defer
可以让代码更加简洁。以下代码模拟了上述4种情况:
package main
import "fmt"
func main() {
doDBOperations()
}
func connectToDB() {
fmt.Println("connected")
}
func disconnectFromDB() {
fmt.Println("disconnected from db")
}
func doDBOperations() {
connectToDB()
fmt.Println("defering the database disconnect")
defer disconnectFromDB() // function called here with defer
fmt.Println("doing some DB operations ...")
fmt.Println("crash or network error ...")
fmt.Println("returning from function here")
return // terminate the program
// deferred function excuted here just before actually returning, even if
// there is a return or abnormal termination before
}
一种基础且十分实用的代码执行追踪方案就是进入和离开某个函数打印相关信息,抽象为下面两个函数:
package main
import "fmt"
func trace(s string) {
fmt.Println("entering: ", s)
}
func untrace(s string) {
fmt.Println("exiting: ", s)
}
func a() {
trace("a")
defer untrace("a")
fmt.Println("in a")
}
func b() {
trace("b")
defer untrace("b")
fmt.Println("in b")
a()
}
func main() {
b()
}
运行结果为:
entering: b
in b
entering: a
in a
exiting: a
exiting: b
package main
import (
"log"
"io"
)
func f1(s string) (n int, err error) {
defer func() {
log.Printf("f1(%q) = %d, %v", s, n, err)
}()
return 7, io.EOF
}
func main() {
f1("Go")
}
输出为:
2021/03/27 12:23:53 f1("Go") = 7, EOF
panic
和recover
是Go的两个内置函数,用于处理Go运行时的错误。panic
用于主动抛出错误,recover
用于捕获panic
抛出的错误。
引发panic
有两种情形,一是程序主动调用,二是程序产生运行时错误,由运行时检测并退出。
发生panic
后,程序会从调用panic
的函数位置或者发生panic
的地方立即返回,逐层向上执行函数的defer
语句,然后逐层打印函数调用堆栈,直到被recover
捕获或运行到最外层函数。
panic
不但可以在函数正常流程中抛出,在defer
逻辑里也可以再次调用panic
或抛出panic
。defer
里的panic
能够被后续执行的defer
捕获。
recover
用来捕获panic
,阻止panic
继续向上传递。recover
和defer
一起使用,但是defer
只有在后面的函数体内直接被调用才能捕获panic
来终止异常,否则返回nil
,异常继续向外传递。
// 捕获失败
defer recover()
defer fmt.Println(recover)
defer func() {
func() {
recover() // 无效,嵌套两层
}()
}()
// 捕获成功
defer func() {
recover()
}()
func except() {
recover()
}
func test() {
defer except()
panic("runtime error")
}
package main
import "fmt"
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
defer func() {
panic("three")
}()
defer func() {
panic("two")
}()
panic("one")
}
一般在以下情况中用到:
panic
打印堆栈,方便定位错误。标签:recover 需要 流程 参数 文件流 puts UNC open 关闭数据库
原文地址:https://www.cnblogs.com/4thrun/p/Golang_5.html