浅谈go中defer的一个隐藏功能
在开始使用Go进行编码时,Defer是要关注的一个很重要的特性。它非常简单:在任何函数中,给其他函数的调用加上前缀defer以确保该函数在外部函数退出之前立即执行,即使外部函数出现异常被中断,该延迟函数也将运行。
但是,你还可以使用defer在任何函数开始后和结束前执行配对的代码。这个隐藏的功能在网上的教程和书籍中很少提到。要使用此功能,需要创建一个函数并使它本身返回另一个函数,返回的函数将作为真正的延迟函数。在defer语句调用父函数后在其上添加额外的括号来延迟执行返回的子函数如下所示:
funcmain(){ defergreet()() fmt.Println("Somecodehere...") } funcgreet()func(){ fmt.Println("Hello!") returnfunc(){fmt.Println("Bye!")}//thiswillbedeferred }
输出以下内容:
Hello!
Somecodehere...
Bye!
父函数返回的函数将是实际的延迟函数。父函数中的其他代码将在函数开始时(由defer语句放置的位置决定)立即执行。
这为开发者提供了什么能力?因为在函数内定义的匿名函数可以访问完整的词法环境(lexicalenvironment),这意味着在函数中定义的内部函数可以引用该函数的变量。在下一个示例中看到的,参数变量在measure函数第一次执行和其延迟执行的子函数内都能访问到:
funcmain(){ example() otherExample() } funcexample(){ defermeasure("example")() fmt.Println("Somecodehere") } funcotherExample(){ defermeasure("otherExample")() fmt.Println("Someothercodehere") } funcmeasure(namestring)func(){ start:=time.Now() fmt.Printf("Startingfunction%s\n",name) returnfunc(){fmt.Printf("Exitingfunction%safter%s\n",name,time.Since(start))} }
输出以下内容:
Startingexample
Somecodehere
Exitingexampleafter0s
StartingotherExample
Someothercodehere
ExitingotherExampleafter0s
此外函数命名的返回值也是函数内的局部变量,所以上面例子中的measure函数如果接收命名返回值作为参数的话,那么命名返回值在延迟执行的函数中访问到,这样就能将measure函数改造成记录入参和返回值的工具函数。
下面的示例是引用《go语言程序设计》中的代码段:
funcbigSlowOperation(){ defertrace("bigSlowOperation")()//don'tforgettheextraparentheses //...lotsofwork… time.Sleep(10*time.Second)//simulateslow operationbysleeping } functrace(msgstring)func(){ start:=time.Now() log.Printf("enter%s",msg) returnfunc(){ log.Printf("exit%s(%s)",msg,time.Since(start)) } }
可以想象,将代码延迟在函数的入口和出口使用是非常有用的功能,尤其是在调试代码的时候。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。