defer 匿名函数特性

  • 执行方式类似其它语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行

    //执行顺序相反
    package main
    import "fmt" func main() {
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c")
    }
    /*输出
    a
    c
    b
    */
  • 即使函数发生严重的错误也会执行,类似于try...except

  • 常用于 资源清理,文件关闭,解锁以及记录时间等操作

  • 支持匿名函数的调用

  • 通过于匿名函数配合可在return之后修改函数计算的结果

    -如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则 则时引用某个变量的地址

    //支持匿名函数
    package main
    import "fmt" func main() {
    for i := 0; i < 3; i++ {
    defer func() { //函数体内的变量传递到defer匿名函数
    fmt.Println(i) //此时引用的时变量i的地址
    }()
    }
    } /*输出
    3
    3
    3
    */
  • Go没有异常机制,但有panic/recover模式来处理错误

  • Panic可以在任何地方引发

    panic错误机制

    //panic 错误机制,遇到panic语句后,后面不会再执行
    package main
    import "fmt"
    func main() {
    A()
    B()
    C()
    } func A() {
    fmt.Println("func a")
    } func B() {
    panic("Panic B")
    }
    func C() {
    fmt.Println("func")
    } /*输出
    A()--> func a
    B()---> panic: Panic B
    ---------------
    goroutine 1 [running]:
    main.B()
    C() C:/Users/faily/Desktop/workspace/src/defer1.go:17 +0x40
    main.main()
    C:/Users/faily/Desktop/workspace/src/defer1.go:8 +0x2c
    exit status 2
    exit status 1
    */
  • defer,配合recover及匿名函数处理程序出现的严重错误(panic语句),调过程序错误,继续执行,类似于python语言中 try...except,finally语句.

    //defer,recover机制,处理panic引发的机制
    package main
    import "fmt" func main() {
    A()
    B()
    C()
    } func A() {
    fmt.Println("func a")
    }
    func B() {
    defer func() { //defer函数放在panic之前
    if err := recover(); err != nil { //注册recover函数(判断是否触发panic错误),并判断
    fmt.Println("Recover in B") //如果程序出现panic,并且err不为nil(真实存在)
    }
    }() //记住,defer的匿名函数大括号后要加上()
    panic("Panic B") //跳过程序错误,继续后面的执行。 }
    func C() {
    fmt.Println("func C") } /*输出
    A()--> func a
    B()--> Recover in B
    C()--> func C
    */

- defer,匿名函数,变量传递,数组array,for循环综合

> 运行以下代码,并分析输出结果

  ```go

  package main

  import "fmt"

  func main() {
var fs = [4]func(){} //定义一个变量fs,类型为一个数组,数组元素的类型是匿名函数func
for i := 0; i < 4; i++ {
defer fmt.Println("defer i=", i) //defer,遵循的是先进后出,所以for循环,最后执行这一句,i作为变量,正常传递
defer func() { fmt.Println("defer closure i=", i) }() // i从外部传递进defer匿名函数中,作为变量而非匿名函数参数,此时引用的是i的内存地址(只会引用i的最后值)
fs[i] = func() { fmt.Println("closure i=", i) } //为fs数组索引赋值,i传递进匿名函数并没有作为参数,所以i引用的是i的内存地址(只会引用i的最后值)
fmt.Println(i)
} for n, f := range fs { // for 循环数组,执行每一个元素(匿名函数)
fmt.Println(n)
f()
}
}
/*输出
n=0
closure i= 4
n=1
closure i= 4
n=2
closure i= 4
n=3
closure i= 4
------------------------
defer closure i= 4
defer i= 3
defer closure i= 4
defer i= 2
defer closure i= 4
defer i= 1
defer closure i= 4
defer i= 0
*/
```

分析结果,详见代码注释

golang基础--细说defer的更多相关文章

  1. 【Golang基础】defer执行顺序

    defer 执行顺序类似栈的先入后出原则(FILO)     一个defer引发的小坑:打开文件,读取内容,删除文件   // 原始问题代码 func testFun(){ // 打开文件 file, ...

  2. Golang基础之函数

    golang基础之函数 1.为什么需要函数? 有些相同的代码可能出现多次,如果不进行封装,那么多次写入到程序中,会造成程序冗余,并且可读性降低 2.什么是函数 为完成某些特定功能的程序指令集合称为函数 ...

  3. Golang 基础之基础语法梳理 (一)

    大家好,今天将梳理出的 Go语言基础语法内容,分享给大家. 请多多指教,谢谢. 本次<Go语言基础语法内容>共分为三个章节,本文为第一章节 Golang 基础之基础语法梳理 (一) Gol ...

  4. Golang基础教程

    以下使用goland的IDE演示,包含总计的golang基础功能共20个章节 一.go语言结构: 二.go基础语法: 三.变量 四.常量 五.运算符 六.条件语句 七.循环 八.函数 九.变量作用域 ...

  5. golang基础知识之encoding/json package

    golang基础知识之json 简介 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式.可以去json.org 查看json标准的清晰定义.json pack ...

  6. GoLang基础数据类型--->字典(map)详解

    GoLang基础数据类型--->字典(map)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   可能大家刚刚接触Golang的小伙伴都会跟我一样,这个map是干嘛的,是 ...

  7. GoLang基础数据类型-切片(slice)详解

    GoLang基础数据类型-切片(slice)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 数组的长度在定义之后无法再次修改:数组是值类型,每次传递都将产生一份副本.显然这种数 ...

  8. GoLang基础数据类型--->数组(array)详解

    GoLang基础数据类型--->数组(array)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Golang数组简介 数组是Go语言编程中最常用的数据结构之一.顾名 ...

  9. GoLang基础数据类型--->字符串处理大全

    GoLang基础数据类型--->字符串处理大全 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 欢迎加入:   高级运维工程师之路               59843264 ...

随机推荐

  1. const 用法全面总结

    C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方面查到的资料进行总结如下,期望对朋友们有所帮助. Const 是C++中常用的类型修饰符,常类型是指使用类 ...

  2. easyui datagrid sort 表头 排序

    datagrid的点击列表头刷新,分为两种,一种是页面刷新,不涉及后台服务器数据,不会从新查询数据库,只会刷新当前页数据: 一种是服务器级刷新,会重新加载全部数据. 如果不需要自定义排序,可以直接使用 ...

  3. 一个钓鱼WiFi的破解

    在开始前我们先安装下工具 git clone [url]https://github.com/P0cL4bs/WiFi-Pumpkin.git[/url] [/size] [size=4][size= ...

  4. mongodb因非法关闭导致无法启动的解决方案

    mongodb因非法关闭导致无法启动的解决方案 1.删除数据库目录的.lock文件 2.输入命令 mongod --repair 3.重启

  5. 微信小程序与vueJs的异同

    简而言之,所有的框架都是建立在原生javascript基础之上的,所以对于有一定js基础的同学来说,各种框架都是比较容易入手的,但不同的框架之间又有一定的差别,有时候切换使用时就会掉入坑了. 一.微信 ...

  6. input 下拉框 的实践

    有一个需求  需要做一个input 框  点击出现列表 于是想到了  datalist控件 <input type="text" list="itemlist&qu ...

  7. 2018新年 flag 了解一下(每月初更新...)

    昨天(2018/3/2)是元宵节,这很恐怖,因为意味着 往后再也找不到这么冠冕堂皇的理由用来偷懒啦~ 嘤嘤嘤~ (我特么反手就是一拳,让你嘤嘤嘤) emm,跑题了. 正文 话说一日之计在于晨,一年之计 ...

  8. jsp页面,jstl标签中的数据在<%%>java中使用

    可参考jsp的API隐式对象.. 这部分数据其实被保存在page域中,但jsp中如果使用java代码需要在特定的标签中<%%>,在这个标签中可使用的只有pageContext对象,所以可以 ...

  9. OC basic

    不能在栈上分配对象 //Interface type cannot be statically allocated NSString stackString; 因为对象所占内存总是分配在"堆 ...

  10. centos7硬盘分区

    首先在虚拟机的设置中为系统添加硬盘 使用fdisk -l /dev/sdb   查看未分区的硬盘 fdisk -l /dev/sda  这是已经分区好得 接下来我们就要对sdb进行分区: 首先使用fd ...