4

go那些事儿|defer必掌握知识

 3 years ago
source link: https://studygolang.com/articles/32851
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

目录

  • defer执行时机
  • defer执行顺序
  • defer与return谁先谁后
  • 函数包含多个Panic,defer中recover处理那个Panic
  • 函数返回值遇到defer
  • defer遇到Panic
    • defer遇到Panic,但是并不捕获异常的情况
    • defer遇到Panic,并捕获异常
  • 练习:defer面试题
  • 闲聊
  • 欢迎加入我的公众号【迈莫coding】 一起pk大厂

defer执行时机

  • return 语句执行完之后,如果有 defer 语句,再执行 defer 语句
  • 发生 Panic ,也会触发 defer 执行

defer执行顺序

多个defer出现时,会以"先进后出,后进先出"的规则来执行,类似于数据结构中栈的执行顺序.

示例:

package main 

import "fmt"func main() {  defer func(){
    fmt.Println("A")
  }()  defer func(){
    fmt.Println("B")
  }  defer func(){
    fmt.Println("C")
  }
}复制代码

结果:

C
B
A复制代码

defer与return谁先谁后

示例代码

package main 

import "fmt"func deferFunc() {
  fmt.Println("defer func")
}func returnFunc() int {
  fmt.Println("return func")  return 1}func returnAndDefer() int {  defer deferFunc()  return returnFunc()
}func main() {
  returnAndDefer()
}复制代码

结果

return funcdefer func复制代码

结论

一个函数中即有return语句,也有defer语句,先执行return语句,后执行defer语句复制代码

函数包含多个Panic,defer中recover处理那个Panic

示例

package mainimport "fmt"func main() {  defer func() {if err := recover(); err != nil {
      fmt.Println(err)
    }else {
      fmt.Println("fail")
    }
  }()  defer func() {panic("defer panic")
  }()  panic("main panic")
}复制代码

结果

defer panic复制代码

结论

只有最后一个panic,可以被recover捕获到.复制代码

函数返回值遇到defer

示例

package mainimport "fmt"func deferFunc() (t int) { // t初始化为0,并且作用域为该函数全域
  defer func() {
    t = t * 10
  }()  return 1}func main() {
  fmt.Println(deferFunc())
}复制代码

结果

10 复制代码

结论

当调用deferFunc()函数时,本应该返回值1,但函数中还有defer语句,
所以在return语句之后,又被defer的匿名函数func函数执行,所以t=t*10被执行。因此返回值为10.复制代码

defer遇到Panic

defer遇到Panic,但是并不捕获异常的情况

示例

package mainimport "fmt"func defer_panic() {  defer func() {
    fmt.Println("defer: panic() 执行1")
  }()  defer func() {
     fmt.Println("defer: panic() 执行2")
  }  panic("发生异常")
  fmt.Println("该条语句无法执行")
}func main() {
  defer_panic()
  fmt.Println("main函数执行完成")
}复制代码

结果

defer: panic() 执行2defer: panic() 执行1panic: 发生异常// 异常信息...复制代码

defer遇到Panic,但捕获异常的情况

示例

package mainimport "fmt"func defer_panic() {  defer func() {
    fmt.Println("defer: panic() 执行1")if err := recover(); err != nil {
      fmt.Println(err)
    }
  }()  defer func() {
     fmt.Println("defer: panic() 执行2")
  }  panic("发生异常")
  fmt.Println("该条语句无法执行")
}func main() {
  defer_panic()
  fmt.Println("main函数执行完成")
}复制代码

结果

defer: panic() 执行2defer: panic() 执行1发生异常
main函数执行完成复制代码

练习:defer面试题

1. 下面代码输出什么?

package mainimport "fmt"func main() {   var name = "zhangsan"
   fmt.Println(name)   defer fmt.Println(name)
   name = "lisa"
   fmt.Println(name)   defer fmt.Println(name)
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

zhangsan lisa lisa zhangsan 
复制代码

2. 程序运行结果

示例

package mainimport (   "fmt")func main() {
   defer_call()
}func defer_call() {   defer func() { fmt.Println("迈") }()   defer func() { fmt.Println("莫") }()   defer func() { fmt.Println("coding") }()
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

coding
莫
迈复制代码

3. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc1(i int) (t int) {
    t = idefer func() {
        t += 3}()return t
}func main() {
    fmt.Println(DeferFunc1(1))
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

4复制代码

执行过程

1. 将返回值t赋值为行参i,t = 12. 执行return语句,将t 赋值给t3. 执行defer语句,t + 3 = 44. 返回值4复制代码

4. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc2(i int) int {
    t := idefer func() {
        t += 3}()return t
}func main() {
    fmt.Println(DeferFunc2(1))
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

1复制代码

执行过程

1. 创建变量t并将其赋值为i的值,t = 12. 执行return语句,注意这里是将t赋值给返回值,此时返回值为1(这个返回值并不是t)3.执行defer语句,t = t + 3 = 44. 函数返回值1复制代码

5. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc3(i int) (t int) {defer func() {
        t += i
    }()return 2}func main() {
    fmt.Println(DeferFunc3(1))
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

3复制代码

执行过程

1. 首先将t赋值为22. 执行defer语句,t = t + 1 = 33. 函数返回值3复制代码

6. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc4() (t int) {defer func(i int) {
        fmt.Println(i)
        fmt.Println(t)
    }(t)
    t = 1return 2}func main() {
    DeferFunc4()
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

02复制代码

执行过程

1. 初始化返回值t为零值 02. 首先执行defer的第一步,赋值defer中的func入参t为03. 执行defer的第二步,将defer压栈4. 将t赋值为15. 执行return语句,将返回值t赋值为26. 执行defer的第三步,出栈并执行7. 因为在入栈时defer执行的func的入参已经赋值了,此时它作为的是一个形式参数,所以打印为0;8. 相对应的因为最后已经将t的值修改为2,所以再打印一个2复制代码

闲聊

  • 读完文章,自己是不是和defer的cp率又提高了
  • 我是迈莫,欢迎大家和我交流

原创不易,觉得文章写得不错的小伙伴,点个赞???? 鼓励一下吧~

有疑问加站长微信联系(非本文作者)

eUjI7rn.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK