标签: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