使用defer关键字的函数返回类型带参数名的时候,返回结果会受影响的原因是什么

来源:2-6 函数

JToGo

2020-02-07

老师:
你好!
今天做面试题的时候发现,函数返回类型带参数名的时候,如果使用的defer关键字,是会影响到最终返回值的。能否讲解一下原理?
比如下面的两段代码:

func DeferFunc1(i int) (t int) {
	t = i
	defer func() {
		t += 3
	}()
	return t
}//这一段代码最终返回结果是3+t
func DeferFunc2(i int) int {
	t := i
	defer func() {
		t += 3
	}()
	return t
}//这一段的返回结果是t
写回答

1回答

ccmouse

2020-02-09

题外话,这么快就出了这种没啥实际作用扣语言细节的题,我不赞成这样的面试题。

回到题目本身,这里返回多少不是人为设计的,而是编译器实现defer,以及命名返回值(t int)后自然的做法。defer函数的执行应该是在return语句之后。

这里有两个关键点:

  1. defer的时机是在return之后。

  2. 命名返回值,就是DeferFunc1里的t,它的生命周期比函数体要大,函数一开始返回的仍然是i,但是这个返回值被defer修改了。我们建议在使用命名返回值的时候,return后面不要带值。这样的写法其实是不可取的,故意误导。

我根据原理等价改写了一下代码:

DeferFunc2中,返回值没有命名,所以编译器分配了个返回值res,用来接返回值。随后的t+=3不影响res。

func DeferFunc2(i int) int {
  var t int
  res := func() int {
     t = i
     return t
  }()
  func() {
     t += 3
  }()
  return res
}

DeferFunc1中,由于命名了返回值为t,就不需要分配变量res,return t实际上是把t的值赋值为return后面的值,后面t+=3就影响了返回值。

func DeferFunc1(i int) (t int) {
  t = func() int {
     t = i
     return t
  }()
  func() {
     t += 3
  }()
  return t
}

1
1
JToGo
非常感谢!
2020-02-29
共1条回复

Google资深工程师深度讲解Go语言 由浅入深掌握Go语言

语法+分布式爬虫实战 为转型工程师量身打造

5995 学习 · 1909 问题

查看课程