zoukankan      html  css  js  c++  java
  • go defer (go延迟函数)

    go defer (go延迟函数)

    Go语言的defer算是一个语言的新特性,至少对比当今主流编程语言如此。根据GO LANGUAGE SPEC的说法:

    A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking. defer语句调用一个函数,这个函数执行会推迟,直到外围的函数返回,或者外围函数运行到最后,或者相应的goroutine panic

    换句话说,每当defer执行的时候,它后面的函数值(在go中函数是一个引用类型,是一等公民,可以赋值给变量)和函数参数会被求值,但是函数不会立即调用,直到(↑)上述三种情况发生。 这就是defer的全部内容,没了,剩下就是defer的best practice

    函数不会立即调用

    先从最简单的开始:

    func readFile(fileName string){
    	f,err := os.Open(fileName)
    	if err!=nil {
    		return
    	}
    	defer f.Close()
    	var content [1024]byte
    	f.Read(content[:])
    	fmt.Printf("%s",content)
    }
    func main() {
    	readFile("test.data")
    }
    

      

    程序输出test.data前1024字节的内容。值得一提的是,类似这种open/close配对操作是defer的惯用法。 这个例子诠释了上面那句话的后半段

    "但是函数不会被调用" 

    因为如果defer后面的f.Close()没有延迟执行,那么文件描述符都关闭了,就不会读取到任何内容。

    函数值和函数参数被求值,但函数不会立即调用

    下面这个例子即将诠释上半段,它来自<>,稍作修改:

    func trace(funcName string) func(){
    	start := time.Now()
    	fmt.Printf("function %s enter
    ",funcName)
    	return func(){
    		log.Printf("function %s exit (elapsed %s)",funcName,time.Since(start))
    	}
    }
    
    func foo(){
    	defer trace("foo()")()
    	time.Sleep(5*time.Second)
    }
    func main(){
        foo()
        foo()
    }
    /*
    OUTPUT:
    function foo() enter
    function foo() exit (elapsed 5.0095471s)
    function foo() enter
    function foo() exit (elapsed 5.0005382s)
    */
    

      

    为什么foo会输出enter然后等待五秒左右再输出exit? 因为正如我们说的,

    defer后面的函数值和参数会被求值但是实际函数调用却要等到最后

    这里函数值就是trace()返回的匿名函数,函数参数当然就是字符串字面值"foo()", 对trace("foo()")的求值会输出function foo() enter, 实际函数调用trace("foo()")()即输出function foo() exit(elapsed x.x)会推迟到return执行(如果return会更新返回值变量,则会在更新后才执行defer的函数)。

    杂项

    多说一点,如果存在多个defer语句,最后的defer的函数的执行顺序与defer出现的顺序相反,如:

    func main() {
    	func1 := func(){
    		fmt.Println("func1() execution deferred")
    	}
    	func2 := func(){
    		fmt.Println("func2() execution deferred")
    	}
    	defer func1()
    	defer func2()
    	fmt.Println("strat
    working...")
    }
    /*
    OUTPUT:
    strat
    working...
    func2() execution deferred
    func1() execution deferred
    */
    

      

  • 相关阅读:
    [JLOI2013]地形生成[组合计数]
    [Luogu1891]疯狂LCM[辗转相减法]
    [BZOJ3745][COCI2015]Norma[分治]
    [BZOJ4028][HAOI2015]公约数数列[分块+分析暴力]
    [BZOJ4476][JSOI2015]送礼物[分数规划+单调队列]
    【JZOJ4893】【NOIP2016提高A组集训第15场11.14】过河
    【JZOJ4890】【NOIP2016提高A组集训第14场11.12】随机游走
    【JZOJ4889】【NOIP2016提高A组集训第14场11.12】最长公共回文子序列
    【JZOJ4888】【NOIP2016提高A组集训第14场11.12】最近公共祖先
    【JZOJ4887】【NOIP2016提高A组集训第13场11.11】最大匹配
  • 原文地址:https://www.cnblogs.com/ysherlock/p/8150726.html
Copyright © 2011-2022 走看看