1:后定义的defer先执行(可以理解为栈的方式)

// 222
// 111
func Test1(t *testing.T) {
defer fmt.Println("111")
defer fmt.Println("222")
}

2:defer定义的函数的参数,在定义的时候已经被赋值了

// defer 函数定义的时候,参数已经被赋值了(参数被捕捉了)

// 输出:
// 第二个defer: 2
// 第一个defer: 1
func Test2(t *testing.T) {
a := 1 // 注意这里,a作为defer函数的参数。defer函数定义的时候,就把a的值确定了
defer fmt.Println("第一个defer: ", a) defer func() {
fmt.Println("第二个defer: ", a)
}() a+=1
}

3:defer函数可以修改具名返回值,但不会修改匿名返回值

/////////////////////////////////////////////////////////
// defer 函数可以修改具名返回值,但是不会修改匿名返回值
// 输出
// fHasName: 2
// fNoName: 1
func fHasName() (val int) {
val = 1
defer func() {
// 因为val是个具名返回值,所以这里对val的操作,会影响到返回值
val += 1
}() return val
}
func fNoName() int {
val := 1
defer func() {
// 这里的操作则不会影响返回值
val += 1
}() return val
}

4:遇到panic的时候,当前协程调用栈已定义的defer将被执行,如果当前协程没有任何一个defer函数内执行了recover,那么执行完所有的defer之后,将会触发panic退出进程

/* 输出
has: 333
err: haha
has: 222
has: 111
*/
func TestHasRecover(t *testing.T) {
defer fmt.Println("has: 111")
defer fmt.Println("has: 222")
defer func() {
if err := recover(); err != nil {
fmt.Println("err:", err)
}
}()
defer fmt.Println("has: 333")
panic("haha")
defer fmt.Println("has: 444")
} /* 输出
has: 333
has: 222
has: 111 panic: haha [recovered]
panic: haha goroutine 19 [running]:
testing.tRunner.func1.1(0x95df20, 0x9b2110)
C:/Go/src/testing/testing.go:1076 +0x310
testing.tRunner.func1(0xc000140480)
C:/Go/src/testing/testing.go:1079 +0x43a
*/
func TestNoRecover(t *testing.T) {
defer fmt.Println("has: 111")
defer fmt.Println("has: 222")
defer fmt.Println("has: 333")
panic("haha")
defer fmt.Println("has: 444")
}

最后来一道总结题,如下代码会输出什么?


import "testing"
import "fmt" func sum(tip string, a int, b int) int {
sum := a + b
fmt.Printf("tip=%s a=%d b=%d sum=%d\n", tip, a, b, sum)
return sum
} func deferSum() {
a := 1
b := 2
defer sum("1tip", a, sum("2tip", a, b))
a = 3
defer func(b int) {
sum("3tip", a, sum("4tip", a, b))
}(a)
b = 4
defer func() {
sum("5tip", a, sum("6tip", a, b))
}()
} func TestDeferSum(t *testing.T) {
deferSum()
}

正确答案如下:

tip=6tip a=3 b=4 sum=7
tip=5tip a=3 b=7 sum=10
tip=4tip a=3 b=3 sum=6
tip=3tip a=3 b=6 sum=9
tip=1tip a=1 b=3 sum=4

go特性-defer的更多相关文章

  1. golang学习 ---defer语句

    golang语言defer特性详解 defer语句是go语言提供的一种用于注册延迟调用的机制,它可以让函数在当前函数执行完毕后执行,是go语言中一种很有用的特性.由于它使用起来简单又方便,所以深得go ...

  2. Python也可以拥有延迟函数

    延迟函数defer 我们知道在Golang中有一个关键字defer,用它来声明在函数调用前,会让函数*延迟**到外部函数退出时再执行,注意,这里的退出含义:函数return返回或者函数panic退出 ...

  3. 浏览器环境下JavaScript脚本加载与执行探析之defer与async特性

    defer和async特性相信是很多JavaScript开发者"熟悉而又不熟悉"的两个特性,从字面上来看,二者的功能很好理解,分别是"延迟脚本"和"异 ...

  4. Go defer 特性和使用场景

    golang 的 defer 语句用于延迟调用.defer 会在当前函数返回之前执行 defer 注册的函数.比如 defer func_defer() 这样语句会让你注册一个函数变量到 defer ...

  5. JS魔法堂:ES6新特性——GeneratorFunction介绍

    一.前言       第一次看koajs的示例时,发现该语句 function *(next){...............} ,这是啥啊?于是搜索一下,原来这是就是ES6的新特性Generator ...

  6. 【Go入门教程3】流程(if、goto、for、switch)和函数(多个返回值、变参、传值与传指针、defer、函数作为值/类型、Panic和Recover、main函数和init函数、import)

    这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和 ...

  7. iOS - Swift Swift 语言新特性

    1.Swift 2.0 带来哪些新变化 常规变化: 1.OS X 10.11.iOS 9 和 watchOS 2 SDK 采纳了一些 Objective-C 的特性用来提高 Swift 的编程体验, ...

  8. HTML5 <script>元素async,defer异步加载

    原文地址:HTML5′s async Script Attribute原文日期: 2010年09月22日翻译日期: 2013年08月22日 (译者注: 异步加载,可以理解为无阻塞并发处理.) (译者再 ...

  9. javascript笔记——js的阻塞特性[转载]

    JS具有阻塞特性,当浏览器在执行js代码时,不能同时做其它事情,即<script>每次出现都会让页面等待脚本的解析和执行(不论JS是内嵌的还是外链的),JS代码执行完成后,才继续渲染页面. ...

随机推荐

  1. Postman测试数据

    一.新增 在controller中编写新增的方法,加上@RequestBody注解,以json格式获取数据 在Postman中,有两种方法新增数据 直接新增参数,如: 以json格式新增 二.删除 根 ...

  2. Java学习的第三十三天

    1.今天复习了第十二章的12.1的文件和12.2一直到12.2.4 2.没有问题 3.明天继续复习

  3. 常用数据结构-namedtuple(命名元祖)

    namedtuple从根本上来说是一个带有数据名称的元祖.它包含元祖的所有特性,但也有一些元祖没有的额外特性.使用namedtuple可以很容易创建轻量级对象类型. namedtuple将是你的代码更 ...

  4. Ubuntu18.04上安装NS-3

    目录 第一步:处理gcc/g++版本 第二步:安装相关依赖 第三步:正式安装 第四步:测试 我自己前后安装过好几次NS3了,网上其他相关的博客质量都不是很好,因此自己总结了一个ns3的安装过程. 首先 ...

  5. c++11-17 模板核心知识(一)—— 函数模板

    1.1 定义函数模板 1.2 使用函数模板 1.3 两阶段翻译 Two-Phase Translation 1.3.1 模板的编译和链接问题 1.4 多模板参数 1.4.1 引入额外模板参数作为返回值 ...

  6. 搞微服务用阿里开源的 Nacos 真香啊!

    本文适合有 Java 基础知识的人群 本文作者:HelloGitHub-秦人 HelloGitHub 推出的<讲解开源项目>系列,今天给大家带来一款开源 Java 版可以实现动态服务发现, ...

  7. 【RabbitMQ-7】RabbitMQ—交换机标识符

    死信队列概念 死信队列(Dead Letter Exchange),死信交换器.当业务队列中的消息被拒绝或者过期或者超过队列的最大长度时,消息会被丢弃,但若是配置了死信队列,那么消息可以被重新发布到另 ...

  8. centos常用指令之-卸载

    卸载centos自带java: rpm -qa|grep java // 查询javax相关 xxxxxxxxxxxxxx # 卸载1.2方式 # 1 yum -y remove java xxxxx ...

  9. 80%人会答错的JS基础面试题

    这套题第一道题难度最大,我第一遍的回答居然也错的,我悲观估计80%的JavaScript从业人员都答不完全准确 []==![] 得到什么? false, 你还需要看看基础 true, 恭喜你答对了,你 ...

  10. 使用css控制table的cellspacing和cellpadding属性

    HTML默认的表格样式之间有间隙,每次为了解决这些问题,总要在table标签里添加cellspacing和cellpadding,你是否也很厌倦这样的写法, 那么有没有对应的CSS属性能达到相同的效果 ...