入门篇 day2 😁

规则学习

  匿名函数

函数作为函数变量使用,甚至可以直接在函数参数声明匿名函数。
即将函数作为参数使用

展开查看示例代码

```
package main
import (
	"fmt"
	"math"
)
func main() {
	// 调用函数,对每个元素进行求平方根操作
	arr := []float64{1, 9, 16, 25, 30}
	visit(arr, func(v float64) {v = math.Sqrt(v); fmt.Printf("%.2f \n", v)})
	// 调用函数,对每个元素进行求平方根操作
	visit(arr, func(v float64) {v = math.Pow(v, 2);fmt.Printf("%.0f \n", v)})
}
// 定义一个函数,遍历切片元素,对每个元素进行处理
func visit(list []float64, f func(float64)) {
	for _, value := range list {
		f(value)
	}
}
```

  闭包

函数的返回值是一个函数,闭包描述了数据的行为。因为外层函数返回值是一个函数,所以虽然调用的外层函数被释放了,但是内层函数没有释放,且内层函数所使用的变量也没有释放。

闭包分析示例

闭包分析示例 闭包分析示例

闭包(closure):
一个外层函数中,有内层函数,回操作外层函数的局部变量(外层函数中的参数,或者外层函数中直接定义的变量)。
并且外层函数的返回值就是这个内层函数。

这个内层函数和外层函数的局部变量,统称为闭包结构。

局部变量的生命周期会发生改变,正常的局部变量随着函数调用而创建,随着函数的结束而销毁
但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还要继续使用

展开查看示例代码

```
package main
import "fmt"
func main() {
	res1 := increment()
	fmt.Printf("%T\n",res1) //func() int
	fmt.Println(res1)
	v1:=res1()
	fmt.Println(v1) //1
	v2:=res1()
	fmt.Println(v2) //2
	res2 := increment()
	fmt.Println(res2)
	v3 := res2()
	fmt.Println(v3) //1
	fmt.Println(res1()) //3
	fmt.Println(res2()) //2
}
func increment() func() int{ //外层函数
	i := 0
	fun := func() int{ //内层函数
		i++
		return i
	}
	return fun
}
```

##  值传递和引用传递的细节问题

Go语言中所有的传参都是值传递(传值),都是一个副本。副本的内容有的是值类型(int、string、bool、array、struct 属于值类型),这样在函数中就无法修改原内容数据;有的是引用类型(pointer、slice、map、chan 属于引用类型),这样就可以修改原内容数据。
是否可以修改原内容数据,和传值、传引用没有必然的关系。在 C++ 中,传引用肯定是可以修改原内容数据的;在Go语言里,虽然只有传值,但是也可以修改原内容数据,因为参数可以是引用类型。
传引用和引用类型是两个概念。虽然Go语言只有传值一种方式,但是可以通过传引用类型变量达到与传引用一样的效果。
值类型:进行值传递的数据类型也叫值类型,存储的是数值本身。
将数据类型传递给其他的变量,传递的是数据的副本(备份)
int,float,string,bool,array
引用类型:理解为存储的数据的内存地址
slice,map。。

参考

Go语言(Golang)教程
千峰教育 go语言视频教程
闭包 视频讲解