golang的log.Fatal()和panic()函数的区别
golang的log.Fatal()和panic()函数的区别
在讲两者区别之前我们先看一下os.Exit()函数的定义:
funcExit(codeint) Exitcausesthecurrentprogramtoexitwiththegivenstatuscode. Conventionally,codezeroindicatessuccess,non-zeroanerror. Theprogramterminatesimmediately;deferredfunctionsarenotrun.
注意两点:
- 应用程序马上退出。
- defer函数不会执行。
再来看log.Fatal函数定义
funcFatal(v...interface{}) FatalisequivalenttoPrint()followedbyacalltoos.Exit(1).
看源代码:go/src/log/log.go
//Fatalisequivalenttol.Print()followedbyacalltoos.Exit(1). func(l*Logger)Fatal(v...interface{}){ l.Output(2,fmt.Sprint(v...)) os.Exit(1) }
总结起来log.Fatal函数完成:
- 打印输出内容
- 退出应用程序
- defer函数不会执行
和os.Exit()相比多了第一步。
再来看内置函数panic()函数定义:
//Thepanicbuilt-infunctionstopsnormalexecutionofthecurrent //goroutine.WhenafunctionFcallspanic,normalexecutionofFstops //immediately.AnyfunctionswhoseexecutionwasdeferredbyFarerunin //theusualway,andthenFreturnstoitscaller.TothecallerG,the //invocationofFthenbehaveslikeacalltopanic,terminatingG's //executionandrunninganydeferredfunctions.Thiscontinuesuntilall //functionsintheexecutinggoroutinehavestopped,inreverseorder.At //thatpoint,theprogramisterminatedandtheerrorconditionisreported, //includingthevalueoftheargumenttopanic.Thisterminationsequence //iscalledpanickingandcanbecontrolledbythebuilt-infunction //recover. funcpanic(vinterface{})
注意几点:
- 函数立刻停止执行(注意是函数本身,不是应用程序停止)
- defer函数被执行
- 返回给调用者(caller)
- 调用者函数假装也收到了一个panic函数,从而 4.1立即停止执行当前函数 4.2它defer函数被执行 4.3返回给它的调用者(caller)
- ...(递归重复上述步骤,直到最上层函数) 应用程序停止。
- panic的行为
简单的总结panic()就有点类似java语言的exception的处理,因而panic的行为和java的exception处理行为就非常类似,行为结合catch,和final语句块的处理流程。
下面给几个例子:
例子1:log.Fatal
packagemain import( "log" ) funcfoo(){ deferfunc(){log.Print("3333")}() log.Fatal("4444") } funcmain(){ log.Print("1111") deferfunc(){log.Print("2222")}() foo() log.Print("9999") }
运行结果:
$gobuild&&./main 2018/08/2017:48:441111 2018/08/2017:48:444444
可见defer函数的内容并没有被执行,程序在log.Fatal(...)处直接就退出了。
例子2:panic()函数
packagemain import( "log" ) funcfoo(){ deferfunc(){log.Print("3333")}() panic("4444") } funcmain(){ log.Print("1111") deferfunc(){log.Print("2222")}() foo() log.Print("9999") }
运行结果:
$gobuild&&./main 2018/08/2017:49:281111 2018/08/2017:49:283333 2018/08/2017:49:282222 panic:4444 goroutine1[running]: main.foo() /home/.../main.go:9+0x55 main.main() /home/.../main.go:15+0x82
可见所有的defer都被调用到了,函数根据父子调用关系所有的defer都被调用直到最上层。 当然如果其中某一层函数定义了recover()功能,那么panic会在那一层函数里面被截获,然后由recover()定义如何处理这个panic,是丢弃,还是向上再抛出。(是不是和exception的处理机制一模一样呢?)
原为链接:https://www.jianshu.com/p/f85ecae6e7df