教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 defer ,panic,recover

defer ,panic,recover

发布时间:2022-03-08   编辑:jiaochengji.com
教程集为您提供defer ,panic,recover等资源,欢迎您收藏本站,我们将为您提供最新的defer ,panic,recover资源
<h1>defer的执行顺序</h1>

多个defer出现的时候,它是一个“栈”的关系,也就是先进后出。一个函数中,写在前面的defer会比写在后面的defer调用的晚。

<pre><code class="lang-go hljs">package main import "fmt" func main() { defer func1() defer func2() defer func3() } func func1() { fmt.Println("A") } func func2() { fmt.Println("B") } func func3() { fmt.Println("C") } //输出结果:C B A </code></code></pre> <h1>defer和return的先后顺序</h1>

return之后的语句先执行,defer后的语句后执行。

<pre><code class="lang-go hljs">package main import "fmt" func deferFunc() int { fmt.Println("defer func called") return 0 } func returnFunc() int { fmt.Println("return func called") return 0 } func returnAndDefer() int { defer deferFunc() return returnFunc() } func main() { returnAndDefer() } //输出 //return func called //defer func called </code></code></pre> <h1>defer 无名返回值 有名返回值</h1> <ul><li>函数返回值初始化
该知识点不属于defer本身,但是调用的场景却与defer有联系,所以也算是defer必备了解的知识点之一。
如 : func DeferFunc1(i int) (t int) {}
其中返回值t int,这个t会在函数起始处被初始化为对应类型的零值并且作用域为整个函数。</li> </ul><pre><code class="lang-go hljs">package main import "fmt" func DeferFunc(i int) (t int) { fmt.Println("t = ", t) return 2 } func main() { DeferFunc(10) } //输出 //t = 0 </code></code></pre> <ul><li>defer、return 和无名的返回值</li> </ul><pre><code class="lang-go hljs">package main func main() { name := run() println("return: name = " name) } func run() (string) { name := "Paul" defer sayHello(&name) name = "John" return name } func sayHello(name *string) { *name = "George" println("Hello " *name) } // 输出 // Hello George // return: name = John </code></code></pre> <ul><li>defer、return 和有名返回值</li> </ul><pre><code class="lang-go hljs">//传指针 package main func main() { name := run() println("return: name = " name) } func run() (x string) { name := "Paul" x = name defer sayHello(&x) name = "John" return name } func sayHello(name *string) { println("Hello " *name) *name = "George" println("Hello " *name) } //输出 //Hello John //Hello George //return: name = George //传值 package main func main() { name := run() println("return: name = " name) } func run() (x string) { name := "Paul" x = name defer sayHello(x) name = "John" return name } func sayHello(name string) { println("Hello " name) name = "George" println("Hello " name) } //输出 //Hello Paul //Hello George //return: name = John </code></code></pre>

说明:defer,return 和返回值三者之间的执行逻辑
return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出

<h1>defer 闭包</h1> <ul><li>闭包是什么
闭包是由函数及其相关引用环境组合而成的实体,即
闭包=函数 引用环境 </li> </ul>

一般的函数都有函数名,但是匿名函数就没有。匿名函数不能独立存在,但可以直接调用或者赋值于某个变量。匿名函数也被称为闭包,一个闭包继承了函数声明时的作用域。在Golang中,所有的匿名函数都是闭包。

有个不太恰当的例子,可以把闭包看成是一个类,一个闭包函数调用就是实例化一个类。闭包在运行时可以有多个实例,它会将同一个作用域里的变量和常量捕获下来,无论闭包在什么地方被调用(实例化)时,都可以使用这些变量和常量。而且,闭包捕获的变量和常量是引用传递,不是值传递。

<pre><code class="lang-go hljs">package main func main() { name := run() println("return: name = " name) } func run() (string) { name := "Paul" aFun := func() { println("Hello " name) name = "George" println("Hello " name) } name = "John" aFun() bfunc:= func() { println("Hello " name) name = "Bobbi" println("Hello " name) } bfunc() return name } //输出 //Hello John //Hello George //Hello George //Hello Bobbi //return: name = Bobbi </code></code></pre> <ul><li>defer与闭包</li> </ul><pre><code class="lang-go hljs">package main func main() { name := run() println("return: name = " name) } func run() (x string) { name := "Paul" aFun := func() { println("Hello " x) x = "George" println("Hello " x) } defer aFun() name = "John" return name } //输出 //Hello John //Hello George //return: name = George package main func main() { name := run() println("return: name = " name) } func run() (x string) { name := "Paul" x = name aFun := func(x string) { println("Hello " x) x = "George" println("Hello " x) } defer aFun(x) name = "John" return name } //输出: //Hello Paul //Hello George //return: name = John </code></code></pre> <h1>defer panic recover</h1>

能够触发defer的是遇见return(或函数体到末尾)和遇见panic。
遇见panic的情况:遍历本协程的defer链表,并执行defer。在执行defer过程中:遇到recover则停止panic,返回recover处继续往下执行。如果没有遇到recover,遍历完本协程的defer链表后,向stderr抛出panic信息。
A. defer遇见panic,但是并不捕获异常的情况

<pre><code class="lang-go hljs">package main import ( "os" "fmt" "time" ) func main() { var user = os.Getenv("USER_") go func() { defer func() { fmt.Println("defer here") }() if user == "" { panic("should set user env.") } }() time.Sleep(1 * time.Second) fmt.Printf("get result %d\r\n", 1) } //输出 //defer here //panic: should set user env. </code></code></pre>

说明:会发现defer中的字符串”defer here”打印出来了,而main流程中的”ger result”没有打印,说明panic坚守了自己的原则:
执行,且只执行,当前goroutine的defer

B.defer遇见panic,并捕获异常

<pre><code class="lang-go hljs">package main import ( "fmt" ) func main() { defer_call() fmt.Println("main 正常结束") } func defer_call() { defer func() { fmt.Println("defer: panic 之前1, 捕获异常") if err := recover(); err != nil { fmt.Println(err) } }() defer func() { fmt.Println("defer: panic 之前2, 不捕获") }() panic("异常内容") //触发defer出栈 defer func() { fmt.Println("defer: panic 之后, 永远执行不到") }() } //输出 //defer: panic 之前2, 不捕获 //defer: panic 之前1, 捕获异常 //异常内容 //main 正常结束 </code></code></pre>

参考:
Golang中的Defer必掌握的7知识点
Golang中defer、闭包以及命名返回值
Golang: 深入理解panic and recover


到此这篇关于“defer ,panic,recover”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang异常处理机制
recover 没有捕获异常_GO语言异常处理机制panic和recover分析
Go 异常处理机制——defer, error, panic, recover
golang中的defer recover panic
Golang - 访问数据库报错后程序继续运行
golang中的defer panic recover
defer ,panic,recover
【Go学习】一道简单Golang面试题中关于panic和defer的执行顺序引发的惨案
Go 学习之路:异常处理defer,panic,recover
Golang模仿try & catch

[关闭]
~ ~