zoukankan      html  css  js  c++  java
  • golang基础--细说defer

    defer 匿名函数特性

    • 执行方式类似其它语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行

      //执行顺序相反
      package main
      import "fmt"
      
      func main() {
      	fmt.Println("a")
      	defer fmt.Println("b")
      	defer fmt.Println("c")
      }
      /*输出
      a
      c
      b
      */
      
    • 即使函数发生严重的错误也会执行,类似于try...except

    • 常用于 资源清理,文件关闭,解锁以及记录时间等操作

    • 支持匿名函数的调用

    • 通过于匿名函数配合可在return之后修改函数计算的结果
      -如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则 则时引用某个变量的地址

      //支持匿名函数
      package main
      import "fmt"
      
      func main() {
      	for i := 0; i < 3; i++ {
      		defer func() { //函数体内的变量传递到defer匿名函数
      			fmt.Println(i) //此时引用的时变量i的地址
      		}()
      	}
      }
      
      /*输出
      3
      3
      3
      */
      
    • Go没有异常机制,但有panic/recover模式来处理错误

    • Panic可以在任何地方引发

      panic错误机制

      //panic 错误机制,遇到panic语句后,后面不会再执行
      package main
      import "fmt"
      func main() {
      	A()
      	B()
      	C()
      }
      
      func A() {
      	fmt.Println("func a")
      }
      
      func B() {
      	panic("Panic B")
      }
      func C() {
      	fmt.Println("func")
      }
      
      /*输出
      A()-->	func a
      B()--->	panic: Panic B
      ---------------
      	goroutine 1 [running]:
      	main.B()
      C()		C:/Users/faily/Desktop/workspace/src/defer1.go:17 +0x40
      	main.main()
      		C:/Users/faily/Desktop/workspace/src/defer1.go:8 +0x2c
      	exit status 2
      	exit status 1
      */
      
    • defer,配合recover及匿名函数处理程序出现的严重错误(panic语句),调过程序错误,继续执行,类似于python语言中 try...except,finally语句.

      //defer,recover机制,处理panic引发的机制
      package main
      import "fmt"
      
      func main() {
      	A()
      	B()
      	C()
      }
      
      func A() {
      	fmt.Println("func a")
      }
      func B() {
      	defer func() { 				            //defer函数放在panic之前
      		if err := recover(); err != nil { 	    //注册recover函数(判断是否触发panic错误),并判断
      			fmt.Println("Recover in B")  //如果程序出现panic,并且err不为nil(真实存在)
      		} 
      	}()							    //记住,defer的匿名函数大括号后要加上()								
      	panic("Panic B") 				   //跳过程序错误,继续后面的执行。
      
      }
      func C() {
      	fmt.Println("func C")
      
      }
      
      /*输出
      A()-->	func a
      B()-->	Recover in B
      C()-->	func C
      */ 
      

    - defer,匿名函数,变量传递,数组array,for循环综合
    > 运行以下代码,并分析输出结果

      ```go
    
      package main
      
      import "fmt"
      
      func main() {
            var fs = [4]func(){}  //定义一个变量fs,类型为一个数组,数组元素的类型是匿名函数func
            for i := 0; i < 4; i++ {
    	defer fmt.Println("defer i=", i) //defer,遵循的是先进后出,所以for循环,最后执行这一句,i作为变量,正常传递
    	defer func() { fmt.Println("defer closure i=", i) }()   // i从外部传递进defer匿名函数中,作为变量而非匿名函数参数,此时引用的是i的内存地址(只会引用i的最后值)
    	fs[i] = func() { fmt.Println("closure i=", i) }   //为fs数组索引赋值,i传递进匿名函数并没有作为参数,所以i引用的是i的内存地址(只会引用i的最后值)
    	fmt.Println(i)
          }
            
            for n, f := range fs {                // for 循环数组,执行每一个元素(匿名函数)
    	fmt.Println(n)
    	f()
          }
    }
    /*输出
    n=0
    	closure i= 4		
    n=1
    	closure i= 4
    n=2
    	closure i= 4
    n=3
    	closure i= 4
    ------------------------
    defer closure i= 4		
    defer i= 3				
    defer closure i= 4
    defer i= 2
    defer closure i= 4
    defer i= 1
    defer closure i= 4
    defer i= 0
    */
    ```
    

    分析结果,详见代码注释

  • 相关阅读:
    (简单) POJ 3414 Pots,BFS+记录路径。
    (简单) POJ 3087 Shuffle'm Up,枚举。
    (简单) POJ 3126 Prime Path,BFS。
    (简单) POJ 1426 Find The Multiple,BFS+同余。
    (简单) POJ 3279 Fliptile,集合枚举。
    (简单) POJ 1278 Catch That Cow,回溯。
    (简单) POJ 2251 Dungeon Master,BFS。
    (简单) POJ 1321 棋盘问题,回溯。
    回溯---输出二叉树中所有从根到叶子的路径
    回溯---在矩阵中寻找字符串
  • 原文地址:https://www.cnblogs.com/failymao/p/9297334.html
Copyright © 2011-2022 走看看