目录


一、匿名返回值

匿名返回值顾名思义,未对函数的返回值作命名,是隐藏的,如下代码:

func anonymousReturnValues() int {
	var res int
	defer func() {
		res++
		fmt.Println("defer")
	}()
	return res
}

上述函数中返回值只指定是int,并未指定返回值名称,必须在函数内部return语句后进行指定返回值名称,不指定则报错!

二、命名返回值

命名返回值顾名思义就是可以给一个函数的返回值指定名字。如果指定了一个返回值的名字,则可以视为在该函数的第一行中隐含的定义了该名字的变量。

如下代码:

func namedReturnValues() (res int) {
	//var s int = 3
	defer func() {
		res++
		fmt.Println("defer")
	}()
        //return s
	return
}

函数返回值指定返回变量名称,并且不需要在return语句后特别指定返回的变量,go在遇到return时会自动将res返回!如果特别指定了返回变量呢?如上代码屏蔽部分,开始定义整形变量s那么最后return s返回的是什么呢?经过测试返回结果如下:

返回: 4,若是没有defer语句则返回:3,可以看出,虽然指定了变量但是最终返回执行的时候应该有如下这样的赋值代码:

res = s,说明命名返回值返回的永远是函数指定的命名返回值res。

三、defer在命名与匿名返回值函数中的表现

这里首先普及下defer的执行机制

  • 包裹defer的函数返回时
  • 包裹defer的函数执行到末尾时
  • 所在的goroutine发生panic时

直接上代码说明:

func anonymousReturnValues() int {
	var res int
	defer func() {
		res++
		fmt.Println("defer")
	}()
	return res
}

func namedReturnValues() (res int) {
	//var s int = 3
	defer func() {
		res++
		fmt.Println("defer")
	}()
	//fmt.Printf("%d\n", s)
	return
}

第一个为匿名返回值函数,第二个为命名返回值函数,各位读者认为返回值分别是多少呢?

返回值分别为0和1,匿名返回0,命名返回1,这是什么原因呢?

这里以匿名返回函数作说明,执行过程如下:

  • 首先函数返回时会自动创建一个返回变量假设为ret,函数返回时要将res赋值给ret,即有ret = res,也就是说ret=0
  • 然后检查函数中是否有defer存在,若有则执行defer中部分,此时就到了res++
  • 最后返回ret

从上面过程可以看到,函数返回的是ret,即0,虽然defer中res++但是是给res做加减,res和ret是两个变量;但是在命名返回值中就会有不一样的结果,因为返回值在函数定义时以经存在,return时不需要再创建另外的变量ret,返回的ret就是res,只有一个变量,所以res++就是给实际返回的ret做加减,最终返回结果当然是1了。

defer在命名和匿名返回函数中表现不一样,这是一个很大的坑,使用中要多多注意。

以上,若有错误,欢迎指正,一块儿学习!!!

武汉加油,中国加油!!!

武汉加油,中国加油!!!

武汉加油,中国加油!!!