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\n",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执行后。

杂项

多说一点,如果存在多个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\nworking...")
}
/*
OUTPUT:
strat
working...
func2() execution deferred
func1() execution deferred
*/

  

原文地址:https://www.cnblogs.com/racaljk/p/8150726.html

时间: 2024-11-13 08:00:05

go defer (go延迟函数)的相关文章

Golang入门教程(十三)延迟函数defer详解

前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在实际应用中,很多 gopher 并没有真正搞明白 defer.return.返回值.panic 之间的执行顺序,从而掉进坑中,今天我们就来揭开它的神秘面纱!话不多说了,来一起看看详细的介绍吧. 基本介绍 延时调用函数的语法如下: defer func_name(param-list) 当一个函数调用

go 延迟函数 defer

defer 语句用于延迟调用指定的函数比如: func outerFunc() { defer fmt.Println("defer 执行") fmt.Println("第一个被打印") } defer 语句最后才会被执行 func printNumbers() { for i :=0 ; i < 5; i++ { defer func() { fmt.Println(i) }() } } 会打印55555延迟函数执行时i已经=5了 func printNum

Go中defer的延迟调用

// code_006_defer_usage project main.go package main import ( "fmt" ) func test(x int) { fmt.Println(100 / x) } func main() { //关键字 defer ?于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行. //注意,defer语句只能出现在函数或方法的内部. fmt.Println("this is a test") defer fmt

Jquery延迟函数

1.setInterval(function(){},[time]) 示例:这是一个模拟进度条的代码,结束后转向另一页面. <script type="text/javascript"> $(function () { var i = 0; var t = 0; setInterval(function () { if (i < 100) { i = i + 5; t++; $("#linepercent").css("height&qu

延迟函数 比sleep效果好

sleep是会阻塞线程的 网上有些延迟函数测试下来还是会阻塞,而接下来推荐的代码则不会 1 2 3 4 5 6 7 8 9 procedure delay(dwMilliseconds:integer); var firsttickcount: longint; begin firsttickcount := gettickcount; repeat application.processmessages; until ((gettickcount - firsttickcount) >= lo

闭包应用之延迟函数setTimeout

根据HTML 5标准,setTimeout推迟执行的时间,最少是5毫秒.如果小于这个值,会被自动增加到5ms. 每一个setTimeout在执行时,会返回一个唯一ID,把该ID保存在一个变量中,并传入clearTimeout,可以清除定时器. 在setTimeout内部,this绑定采用默认绑定规则,也就是说,在非严格模式下,this会指向window:而在严格模式下,this指向undefined. 一.用setTimeout代替setInterval 由于setInterval间歇调用定时器

unity3D延迟函数

1.Invoke(string methodName,float time) 在一定时间调用methodName函数 using UnityEngine; using System.Collections; public class example : MonoBehaviour { 函数 public void Awake() { Invoke("函数名",时间); } } 2.InvokeRepeating(string methodName,float time,float re

延迟函数

var delayFn={ flag:+new Date().getTime(), mt:null, set:function(fn,delaytime){ var self=this, now=+new Date().getTime(), fc=now-self.flag; (fc>delaytime)&&(clearTimeout(self.mt),self.mt=window.setTimeout(function(){fn.call(null)},500),self.flag

Golang defer

defer 作用: 作为函数的进入与退出的log日志:// Test project main.go 代码如下 package main import ( "fmt" ) func begin(funName string) string { fmt.Println("Enter Function") return funName } func end(funName string) string { fmt.Println("Leave Function