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
*/
```

分析结果,详见代码注释

posted @ 2018-07-11 23:40  failymao  阅读(...)  评论(...编辑  收藏