原文链接:http://www.zhoubotong.site/post/50.html
defer语句用于延迟函数调用,每次会把一个函数压入栈中,函数返回前再把延迟的函数取出并执行。延迟函数可以有参数:
延迟函数的参数在defer语句出现时就已确定下来(传值的就是当前值)
return先赋值(对于命名返回值),然后执行defer,最后函数返回
延迟函数执行按后进先出顺序执行
延迟函数可操作主函数的变量名返回值(修改返回值)
defer后面的表达式可以是func或者是method的调用,如果defer的函数为nil,则会panic
日常开发中,使用不当很容易造成意外的“坑”。下面我整理了下常规使用场景下,defer的问题可能的踩坑汇总。
defer 语句正好是在函数退出时执行的语句,所以使用 defer 能非常方便地处理资源释放、句柄关闭等问题。
package main
import (
"fmt"
"os"
)
func fileSize(filename string) int64 {
f, err := os.Open(filename)
if err != nil {
return 0
}
// 延迟调用Close, 此时Close不会被调用
defer f.Close()
info, err := f.Stat()
if err != nil {
// defer机制触发, 调用Close关闭文件
return 0
}
size := info.Size()
// defer机制触发, 调用Close关闭文件
return size
}
func main() {
fmt.Println(fileSize("demo.txt"))
}
defer中的变量会被提前捕获,后续的修改不会影响到已捕获的值,举个例子:
package main
import (
"fmt"
)
func main() {
i := 0
defer fmt.Println("Defer运行值:", i)
i = 10 // 这里虽然修改了值,但是不会影响上面的i值
fmt.Println("最后输出值:", i)
}
结果defer语句中打印的值是修改前的值。:
最后输出值: 10
Defer运行值: 0
在defer中修改具体变量名返回值时,会影响到函数的实际返回值,继续举个例子:
package main
import (
"fmt"
)
func ShowDefer() {
fmt.Println("最后输出值:", deferValue())
}
func deferValue() (ret int) { // 注意这里返回res变量值
ret = 0
defer func() { // 会直接修改栈中对应的返回值
ret += 10
fmt.Println("Defer 运行值:", ret)
}()
ret = 2
fmt.Println("Ret重置值:", ret)
return //返回的ret最后是 其实是本次2+上面的ret+=10的结果
}
func main() {
ShowDefer()
}
//Ret重置值: 2
//Defer 运行值: 12
//最后输出值: 12
当函数为非具体名返回值时,defer无法影响返回值(因在return时,对应返回值已存入栈中),继续举个例子:
package main
import (
"fmt"
)
func ShowDefer() {
fmt.Println("最后输出值:", deferValue())
}
func deferValue() int { // 非命名变量返回
ret := 0
defer func() {
ret += 10
fmt.Println("Defer 运行值:", ret)
}()
ret = 2
return ret // 这里直接返回ret2
}
func main() {
ShowDefer()
}
//Defer 运行值: 12
//最后输出值: 2
经过上面的实践理解,我们来看下下面的笔试题:
package main
import "fmt"
func f() (result int) {
defer func() {
result *= 7
}()
return 3
}
func main() {
fmt.Println(f())
}
问题解析:这里return先给result赋值为3,之后执行defer,result变为21,最后返回21。
package main
import "fmt"
func f() int {
result := 3
defer func() {
result *= 7
}()
return result
}
func main() {
fmt.Println(f())
}
问题解析:这里return确定返回值3,之后defer才修改result,最后函数返回return确定的返回值3。
package main
import "fmt"
// 多个defer
func multiDefer() {
for i := 3; i > 0; i-- {
defer func(n int) {
fmt.Print(n, " ")
}(i)
}
for i := 33; i > 30; i-- {
defer fmt.Print(i, " ")
}
}
func main() {
multiDefer()
}
问题解析:多个defer函数,按顺序逆序执行,这里输出31 32 33 1 2 3 。
package main
import "fmt"
var fun func() string
func main() {
fmt.Println("hello monkey")
defer fun()
}
问题解析:由于这里的defer指定的func为nil,所以会panic 。
package main
import "fmt"
func main() {
for i := 3; i > 0; i-- {
defer func() {
fmt.Print(i, " ")
}()
}
}
问题解析:这里是极度容易踩坑的地方,由于defer这里调用的func没有参数,等执行的时候,i已经为0(按3 2 1逆序,最后一个i=1时,i--的结果最后是0),所以这里输出3个0 。
如果还不太好理解?
package main
import "fmt"
func main() {
for i := 3; i > 1; i-- { // 循环满足条件的是 3 2,
defer func() { // 因为func 没有参数,defer运行最后i--即 2-- 结果为 1
fmt.Print(i, " ") // 循环2次 结果均为 1
}()
}
}//输出 1 1
按照常规的思维理解应该是这样:
package main
import "fmt"
func main() {
for i := 3; i > 0; i-- {
defer func(i int) {
fmt.Print(i, " ")
}(i)
}
}
感兴趣的朋友可以细细品下。
安全产品安全网关类防火墙Firewall防火墙防火墙主要用于边界安全防护的权限控制和安全域的划分。防火墙•信息安全的防护系统,依照特定的规则,允许或是限制传输的数据通过。防火墙是一个由软件和硬件设备组合而成,在内外网之间、专网与公网之间的界面上构成的保护屏障。下一代防火墙•下一代防火墙,NextGenerationFirewall,简称NGFirewall,是一款可以全面应对应用层威胁的高性能防火墙,提供网络层应用层一体化安全防护。生产厂家•联想网御、CheckPoint、深信服、网康、天融信、华为、H3C等防火墙部署部署于内、外网编辑额,用于权限访问控制和安全域划分。UTM统一威胁管理(Un
2022年10月21日星期五【数据指标】加密货币总市值:$0.95万亿BTC市值占比:38.51%恐慌贪婪指数:23极度恐慌 【今日快讯】1、【政讯】1.1.1、美联储布拉德:市场预期美联储11月会加息75个基点1.1.2、美联储哈克:将维持加息一段时间1.2、美国10年期国债收益率触及4.197%,为2008年6月以来最高1.3、法国数字转型部长:政府将专注于DeFi和Web31.4、巴西ATM机将于11月3日起支持USDT1.5、美众议院副议长将于11月初加入a16zCrypto担任政府事务主管1.6、香港数字资产托管机构FirstDigitalTrust首席执行官:香港仍是安全
文章目录1、考试介绍2、软考网络工程师前景3、软考网络工程师考试内容4、华为命令总结1、考试介绍软考是一个以考试代替评职称的考试,每年都会举行两次考试,一般都在5月份和11月份考试,今年我们的省份取消了考试。具体参考官网中国计算机技术职业资格网可以在上面查看报考时间和报名等。本人准备2021年下半年全国计算机技术与软件专业技术中网络工程师,谁知道疫情就来的很巧,辛辛苦苦复习了三个月,终于整明白头绪了,但是天不遂人愿,疫情导致取消了考试,但是是害怕我是去捐款的吗?2、软考网络工程师前景随着计算机的远程信息化处理应用的高速发展和广泛应用,网络已成为经济发展的强大动力。计算机网络工程是计算机技术和通
1.了解监管机构已经卷到需要监控进程了,为了跟上通报步伐查了下资料,打算浅试一下camille,依据原作的文档初步了解到需要python3、adb、frida、模拟器(木木-已成功、夜神)、root手机,开始逐个尝试,记录一下所遇到的情况。 原作祭上:camille/use.mdatmaster·zhengjim/camille·GitHubhttps://www.cnblogs.com/zhengjim/p/15508738.html2.PythonPython38、pip更新电脑中如果有多个python环境的,记得改好名哦,不然会报错,我是配置了环境变量然后让38的置顶pip如果久没用了也
2022年C++面试题【常问重点问题】`1、请你说说GET和POST的区别?``2、简述一下C++中的多态?``3、说一说进程有多少种状态,如何转换?``3、请你说说指针和引用的区别``4、简述一下虚函数的实现原理``5、说一说vector和list的区别,分别适用于什么场景?``6、什么是孤儿进程,什么是僵尸进程,如何解决僵尸进程``7、请你说说C++Lambda表达式用法及实现原理``8、请你说说innodb和myisam的区别``9、请你说说数据库的索引是什么结构,为什么不用哈希表?``10、虚析构函数有什么作用?``11、说一说常用的Linux命令?(常见)``12、简述一下堆和栈的区
这是我的基本情况:functionsomePostThing(){return$post("/someUrl").done(doSomething);}functiondoSomething(data){//dostuffwiththedata}varobject={};object.deferred=somePostThing();//Afewcycleslater,object.deferredmayberesolvedorunresolvedobject.deferred.done(function(){/*...*/});最后一行可能有效也可能无效,因为在延迟对象已经解析的情况
我有一个关于dojo/Deferred的问题。我将从问题开始,然后详细说明我在做什么:有没有办法不管延迟的结果如何都执行相同的代码行,有点像try...catch语句中的finallyblock?从我读过的内容来看,似乎没有,但也许我对文档的理解有误,并想与SO社区进行验证。这是我正在做的:在Dojo1.9(也适用于1.8)中,我在加载一些数据之前为ContentPane实例化了一个dojox.widget.Standby(加载覆盖)。延迟调用完成后,我想隐藏我的叠加层,如下所示:standby=newStandby({...//standbyprops});this.addChild
我正在jQuery中进行一系列连续的AJAX调用,使用的是与Deferred链接的常用方法。第一次调用返回值列表,后续调用使用这些返回的列表条目进行。在第一次调用返回列表后,后续调用可以按任何顺序进行,但必须一次进行一次。所以这就是我使用的:$.when(callWebService()).then(function(data){varlooper=$.Deferred().resolve(),myList=JSON.parse(data);for(variinmyList){(function(i){looper=looper.then(function(){//Successret
我希望在JavaScript/jQuery中对任意数量的可能可选的函数调用进行排队。例如,在运行第二个(或第三个、第四个等)函数或AJAX调用之前,我可能需要确保用户已通过身份验证并设置了cookie。我研究了使用最近添加的jQuery.Deferred来执行此操作,但发现触发调用的顺序无关紧要(真正的异步样式)。另外,我读到一旦Deferred实例被解析,就不可能取消解析它。这就是我目前所处的位置。最初,我考虑将Deferred实例设置为已解析,然后在堆栈中出现可选函数时取消解析它。vard=$.Deferred(),chained=d,d.resolve(),div=extra.f
我对AngularJSdeferred和$q感到困惑。我找到了这个SOQuestion这解释了$q.defer()和$q之间的区别。它解释了$q.rejectisashortcuttocreateadeferredandthenrejectitimmediately所以$q.reject()必须等于vardeferred=$q.defer();deferred.reject(),如果不是请说明两者的实际区别。但在我的例子中,$q.reject()正在工作,但是deffered.reject()没有工作。我们还需要像$q.reject()但不是deferred.reject()那样返回被