package main

// defer延迟处理函数和return的结合运用
/*	按照下面的示例作了一个总结,文字结合下面的代码更容易理解
	总结一下规则:
		defer里面的变量必须与函数定义的返回值变量是同一个变量才会在最后的时候return defer自执行函数操作后的结果。
		不满足这个条件,return的结果就不是defer自执行函数操作后的结果。return变量的类型要和函数的返回值类型保持一致,不然会报编译错误。
		用变量的内存地址来理解,真的一切都很easy了.
*/

// int 类型默认的初始值是0.
// 匿名返回值函数和命名返回值函数结合return、defer自执行函数的使用,执行结果是不一样的。示例如下:

import "fmt"

func f1() int { // 匿名返回值
	/*	匿名返回值定义:函数定义的返回值只有类型没有名称。此处f1()函数的返回值就只有类型int.

		匿名返回值里面,函数的返回值不是defer自执行函数操作以后的值,所以会直接返回x的值为5.
	*/
	x := 5
	defer func() {
		x++
	}()
	return x
}

func f2() (x int) { // 命名返回值
	/*	命名返回值定义:函数定义的返回值具有名称和类型。此处f2()函数的返回值不仅有名称x,还有类型int.

		在我们的命名返回值里面,函数的返回值是defer自执行函数操作以后的值。
		【但是需要注意defer里面的变量x需要和f2()函数返回值(x int)的变量x是相同的变量,不然此处不成立,此处可以结合f4()来理解.】

		在f4()函数中defer的自执行函数默认传入了变量x,x 又赋值给defer自执行函数的参数y进行了内部y++运算,
		此时defer自执行函数操作以后的y++的结果就不能作为f4()函数的返回值。原因就是x作为参数传入到defer自执行函数中赋值给了y变量,
		就相当于a=1, b=a ,因为Go语言中int是值类型,虽然a把值赋值给了b,即使值相同,但是此时a和b已经是两个独立的变量,都有自己独立的内存地址,互不影响。

	*/
	defer func() {
		x++
	}()
	return 5 // 这个函数的返回值就是defer自执行函数操作以后的值,则结果为6.
}
func f3() (y int) { // 命名返回值
	x := 5
	defer func() {
		x++
	}()
	return x // 这个返回的结果是5,因为x和y是两个不同的变量,虽然类型相同但是内存地址不同,返回的结果就不是defer操作以后的结果了。
}
func f4() (x int) { // 命名返回值
	/*	int是值类型,赋值给新的变量,就会开辟新的内存地址,虽然两者的值相同,但是内存地址不同,两者是完全独立的两个变量。
		x 虽然赋值给了y,但是他们本质上是两个独立的变量。y的内存地址和x的内存地址完全不同,就不能将defer操作后的变量y作为f4()函数的返回值,
		所以这里面返回值的结果是数字5
	*/
	defer func(y int) {
		/*
			1. 此处声明一下:这里面就算写的是defer func(x int),这里面的x和作为defer函数传入的x,也已经不是同一个,
					defer里面相当于把传入参数x的值赋值给了defer函数中的x,做了一次赋值操作
			2. defer和return结合使用的规则:
					defer里面的变量必须与函数定义的返回值变量是同一个变量才会在最后的时候return defer自执行函数操作后的结果。
					不满足这个条件,return的结果就不是defer自执行函数操作后的结果。return变量的类型要和函数的返回值类型保持一致,不然会报编译错误。
		*/
		fmt.Println("此处y的内存地址是:", &y) // 此处y的内存地址是: 0xc0000a6098
		y++
		println("看看这个y是多少:", y) // 结果y的值是2,若把y改成x,结果照样也是2
	}(x + 1)
	fmt.Println("此处x的内存地址是:", &x) // 此处x的内存地址是: 0xc0000a6090
	return 5                              // 这个地方的return 5 就相当于 把5赋值给了f4()函数的返回值x
}

func f5() int { // 匿名返回值
	/*
		defer里面的变量必须与函数定义的返回值变量是同一个变量才会在最后的时候return defer自执行函数操作的结果。
		不满足这个条件,return的结果就不是defer自执行函数操作后的结果。return变量的类型要和函数的返回值类型保持一致,不然会报编译错误。
	*/
	x := 30
	defer func(m int) {
		m++
	}(x)
	return x // 这个匿名返回值的结果是30
}

// ***   主函数	***
func main() {
	fmt.Println(f1())
	fmt.Println(f2())
	fmt.Println(f3())
	fmt.Println(f4())
	fmt.Println(f5())
	// 上面的全部代码执行结果是:
	//	5
	//	6
	//	5
	//	此处x的内存地址是: 0xc0000a6090
	//	此处y的内存地址是: 0xc0000a6098
	//	看看这个y是多少: 1
	//	5
	//	30

}