来源:自学PHP网 时间:2019-08-07 16:47 作者:小飞侠 阅读:次
[导读] golang中defer的使用规则详解...
前言 在golang当中,defer代码块会在函数调用链表中增加一个函数调用。这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数调用。因此,defer通常用来释放函数内部变量。 为了更好的学习defer的行为,我们首先来看下面一段代码: func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } dst, err := os.Create(dstName) if err != nil { return } written, err = io.Copy(dst, src) dst.Close() src.Close() return } 这段代码可以运行,但存在'安全隐患'。如果调用 func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst, src) } 通过defer,我们可以在代码中优雅的关闭/清理代码中所使用的变量。defer作为golang清理变量的特性,有其独有且明确的行为。以下是defer三条使用规则。 规则一 当defer被声明时,其参数就会被实时解析 我们通过以下代码来解释这条规则: func a() { i := 0 defer fmt.Println(i) i++ return } 上面我们说过,defer函数会在return之后被调用。那么这段函数执行完之后,是不用应该输出1呢? 读者自行编译看一下,结果输出的是0. why? 这是因为虽然我们在defer后面定义的是一个带变量的函数: func a() { i := 0 defer fmt.Println(0) //因为i=0,所以此时就明确告诉golang在程序退出时,执行输出0的操作 i++ return } 为了更为明确的说明这个问题,我们继续定义一个defer: func a() { i := 0 defer fmt.Println(i) //输出0,因为i此时就是0 i++ defer fmt.Println(i) //输出1,因为i此时就是1 return } 通过运行结果,可以看到defer输出的值,就是定义时的值。而不是defer真正执行时的变量值(很重要,搞不清楚的话就会产生于预期不一致的结果) 但为什么是先输出1,在输出0呢? 看下面的规则二。 规则二 defer执行顺序为先进后出 当同时定义了多个defer代码块时,golang安装先定义后执行的顺序依次调用defer。不要为什么,golang就是这么定义的。我们用下面的代码加深记忆和理解: func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } } 在循环中,依次定义了四个defer代码块。结合规则一,我们可以明确得知每个defer代码块应该输出什么值。 安装先进后出的原则,我们可以看到依次输出了3210. 规则三 defer可以读取有名返回值 先看下面的代码: func c() (i int) { defer func() { i++ }() return 1 } 输出结果是12. 在开头的时候,我们说过defer是在return调用之后才执行的。 这里需要明确的是defer代码块的作用域仍然在函数之内,结合上面的函数也就是说,defer的作用域仍然在c函数之内。因此defer仍然可以读取c函数内的变量(如果无法读取函数内变量,那又如何进行变量清除呢....)。 当执行return 1 之后,i的值就是1. 此时此刻,defer代码块开始执行,对i进行自增操作。 因此输出2. 掌握了defer以上三条使用规则,那么当我们遇到defer代码块时,就可以明确得知defer的预期结果。 总结 以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对自学php网的支持。 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com