zoukankan      html  css  js  c++  java
  • go 关键字之 defer

    我是谁

    defer - 顾名思义翻译过来叫 延迟, 所以我们通常称呼 defer func() 这样 defer 后面紧跟的函数为 延迟函数.

    作者注: 不过从实际应用来讲, 延迟函数通常用来做一些函数最终返回前的一些收尾工作, 所以称呼为收尾函数其实更贴切.

    三围几何

    defer 有其独特的一面, 了解其个性, 才能更好的下手...对待妹纸, 应该也是这么个理

    延迟性

    顾名思义, 既然叫延迟函数, 那么肯定具备延迟性.

    我们来看看怎么个延迟法, defer_defer.go

    // defer_defer.go
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	foo()
    }
    
    func foo() {
    	fmt.Println(1)
    	defer fmt.Println(2)
    	fmt.Println(3)
    }
    
    // go run defer_defer.go
    // 1
    // 3
    // 2
    
    

    可以看到 defer 定义的延迟函数最后才执行.

    再来个例子, 如果一个函数内出现多个延迟函数, 延迟函数的执行顺序又是怎么样的呢?

    defer_filo.go

    // defer_filo.go
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	foo()
    }
    
    func foo() {
    	defer fmt.Println(1)
    	defer fmt.Println(2)
    	defer fmt.Println(3)
    }
    
    // go run defer_filo.go
    // 3
    // 2
    // 1
    
    

    可以看到先定义的延迟函数后执行, 后定义的延迟函数先执行, 符合栈 (stack) 的先进后出 (FILO) 原则.

    影响性

    直接看代码, defer_impact.go

    // defer_impact.go
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	fmt.Println(foo())
    }
    
    func foo() (result int) {
    	defer func() {
    		result++
    	}()
    	return 0
    }
    
    // go run defer_defer.go
    // 1
    
    

    结果是不是跟想象有点不一样? 上述 foo() 可以改写为下:

    func foo() (result int) {
    	result = 0
    	result++
    	return
    }
    

    go 中的 return 语句不是原子操作.

    go 中 return 语句的操作过程为:

    • 设置返回值
    • 执行延迟函数
    • 真正 return

    所以延迟函数会影响主函数的返回值, 当然还要区分具名返回值/匿名返回值, 后话再说.

    确定性

    延迟函数的参数值, 在延迟函数首次出现时就确定了, 不受后续操作的影响.

    我们来个例子: defer_parameters.go

    // defer_parameters.go
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	foo()
    }
    
    func foo() {
    	number := 1
    	defer fmt.Println(number)
    	number = 2
    	return
    }
    
    // go run defer_parameters.go
    // 1
    

    能做啥

    • 打开数据链接, 要记得关闭, 可以用 defer
    • 操作完内存资源, 要记得释放, 可以用 defer
    • 想改变主函数的具名返回值, 可以用 defer - 通常不会这么干
    • 想奇淫技巧, 可以用 defer - 偶尔 show 偶尔爽, 一直 show 一直爽
    • 想搞事情, 可以用 defer - 请自行确保生命和财产安全
    • ...

    参考:

  • 相关阅读:
    Codeforces 1009F Dominant Indices
    UOJ #35 后缀排序 哈希做法
    bzoj 3670 [Noi2014]动物园
    动态规划 笔记

    常用模块和面向对象 类
    常用模块
    包的使用和常用模块
    日志
    复习列表,模块
  • 原文地址:https://www.cnblogs.com/taadis/p/go-defer.html
Copyright © 2011-2022 走看看