分享

Go实战

 菌心说 2021-09-05

原址

生命不止,继续 go go go !!!

学习golang这么久了,还没看到类似传统的 try…catch…finally 这种异常捕捉方式。 
但是,Go中引入的Exception处理:defer, panic, recover。

那么今天跟大家分享一下golang中的defer。闲言少叙,看一下defer的作用:

Defer is used to ensure that a function call is performed later in a program’s execution, usually for purposes of cleanup. defer is often used where e.g. ensure and finally would be used in other languages.

defer的思想类似于C++中的析构函数,不过Go语言中“析构”的不是对象,而是函数,defer就是用来添加函数结束时执行的语句。注意这里强调的是添加,而不是指定,因为不同于C++中的析构函数是静态的,Go中的defer是动态的。

引自:http://www.cnblogs.com/ghj1976/archive/2013/02/11/2910114.html

说多无用,想来个开胃菜,看看如何使用:

  1. package main
  2. import 'fmt'
  3. func main() {
  4. defer goodbye()
  5. defer goodnight()
  6. fmt.Println('Hello world.')
  7. }
  8. func goodnight() {
  9. fmt.Println('GoodNight')
  10. }
  11. func goodbye() {
  12. fmt.Println('Goodbye')
  13. }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

输出: 
Hello world. 
GoodNight 
Goodbye

看出什么了吗? 
**defer在函数结束之前执行 
多个defer的执行顺序: Multiple defers are stacked last-in first-out so that the most recently deferred function is run first.**

那么defer之前就return了呢?

package mainimport 'fmt'func main() {fmt.Println('Hello world.')returndefer goodbye()defer goodnight()}func goodnight() {fmt.Println('GoodNight')}func goodbye() {fmt.Println('Goodbye')}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

输出: 
Hello world. 
defer是在return之前执行的

defer用于关闭文件

  1. package main
  2. import 'fmt'
  3. import 'os'
  4. func main() {
  5. f := createFile('/tmp/defer.txt')
  6. defer closeFile(f)
  7. writeFile(f)
  8. }
  9. func createFile(p string) *os.File {
  10. fmt.Println('creating')
  11. f, err := os.Create(p)
  12. if err != nil {
  13. panic(err)
  14. }
  15. return f
  16. }
  17. func writeFile(f *os.File) {
  18. fmt.Println('writing')
  19. fmt.Fprintln(f, 'data')
  20. }
  21. func closeFile(f *os.File) {
  22. fmt.Println('closing')
  23. f.Close()
  24. }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

defer用于锁

func Divide(i int) error {mu.Lock()defer mu.Unlock()if i == 0 {return errors.New('Can't divide by zero!')}val /= ireturn nil}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

defer中的坑儿

看下面的代码:

  1. package main
  2. import (
  3. 'fmt'
  4. )
  5. func main() {
  6. fmt.Println(f())
  7. fmt.Println(f1())
  8. fmt.Println(f2())
  9. }
  10. func f() (result int) {
  11. defer func() {
  12. result++
  13. }()
  14. return 0
  15. }
  16. func f1() (r int) {
  17. t := 5
  18. defer func() {
  19. t = t + 5
  20. }()
  21. return t
  22. }
  23. func f2() (r int) {
  24. defer func(r int) {
  25. r = r + 5
  26. }(r)
  27. return 1
  28. }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

输出: 


1

要使用defer时不踩坑,最重要的一点就是要明白,return xxx这一条语句并不是一条原子指令! 
函数返回的过程是这样的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。 
defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多