匿名函数
- 匿名函数没有函数名,只有函数体,函数可以被作为一种类型被赋值给变量,匿名函数也往往以变量的方式被传递。
- 匿名函数经常被用于实现回调函数、闭包等。
- 定义格式如下:
func(参数列表)(返回参数列表){
//函数体
}
- 方式一:在定义时调用匿名函数
func anonymousFunc1() {
func(data int) {
fmt.Println("hello", data)
}(100)
}
这里的100是匿名函数的参数
- 方式二:将匿名函数赋值给变量
func anonymousFunc2() {
f := func(data string) {
fmt.Println(data)
}
f("heelo")
}
i2 := func(x, y int) int { return x + y }(1,2)
如上,定义一个匿名函数,包含两个参数x,y
。返回x+y
的结果。后面()
,里面表示参数,参数是:x=1,y=2
。
当然你也可以先定义匿名函数,不使用,等你需要使用的时候,像调用函数一样传参数就可以:
func anonymousFunc5() {
var x, y int
x = 1
y = 2
i2 := func(x, y int) int { return x + y }
i3 := i2(x, y)
fmt.Println(i3)
}
两种函数的区别在于(x,y)
参数在哪里。
- 方式三:有返回参数的后面必须有
return
func anonymousFunc3() {
aaa := func(data int) int {
return data
}
fmt.Println(aaa(1))
}
闭包函数
在代码中,函数若f2被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但反过来就不行,f2的局部变量对f1是不可见的。这就是:链式调用
因为fs2可以读取f1中的局部变量,所以只要把f2作为返回值,我们就可以在f1外部读取f2的内部变量了
闭包:定义在函数内部的函数,在本质上,闭包是将函数内部(f2的变量)和函数外部(f1的变量)连接起来的桥梁(在go语言中匿名函数就是闭包)
闭包的实现:确保只要闭包在使用,那么被闭包引用的变量会一直存在
闭包经常用于回调函数,当IO操作(例如从网络获取数据、文件读写)完成的时候,会对获取的数据进行某些操作,这些操作可以交给函数对象处理。
func test() {
a := 5
b := func()(func()){
c := 10
return func() {
fmt.Printf("a,c: %d,%d \n",a,c)
a *= 3
}
}()
b()
println(a)
}
输出:
a,c: 5,10
15
解释一下
匿名函数的返回值是一个匿名函数,return返回的是一个匿名函数,注意没有加(),所以是用return接收。
然后在最外层加了()
。所以将匿名函数的值给了b
。注意了此时的b
其实是一个函数如下图所示,所以调用的时候是b()
。
尝试将匿名函数的最外层的()去掉:
func test() {
a := 5
b := func()(func()){
c := 10
return func() {
fmt.Printf("a,c: %d,%d \n",a,c)
a *= 3
}
}
fmt.Printf("打印b()类型为:%T\n打印b()值为%v\n",b(),b())
println(a)
输出:
打印b()类型为:func()
打印b()值为0x477180
5
}
此时b
的是一个值,类型如下所示:
在试一下b()()打印:
func test() {
a := 5
b := func()(func()){
c := 10
return func() {
fmt.Printf("a,c: %d,%d \n",a,c)
a *= 3
}
}
b()()
println(a)
}
输出:
a,c: 5,10
15
此b()()
为函数,
注意:a在匿名函数内是可以引用的,但是你如果在匿名函数外引用c,你会发现找不到。并且在闭包内改变了a的值也是会作用到a真实的内存地址中的。
回调函数:
回调函数就是一个被作为参数传递的函数。
package main
import (
"fmt"
)
func main() {
arr :=[]float64{1,2,3,4,5,6}
a :=filterSlice(arr, func(f float64) string {
return fmt.Sprint(f)
})
fmt.Println("a",a)
anonymousFunc()
}
type myFunc1 func(f float64) string
//作为回调函数
//先遍历一个切片,对切片进行操作的函数
func filterSlice(arr []float64, f myFunc1) []string {
//定义一个切片类型的字符串
var result []string
for _, val := range arr {
result = append(result, f(val))
}
fmt.Println("result",result)
return result
}
//对这个函数进行回调使用
//1.回调函数就是一个被作为参数传递的函数
//2.函数中有一个参数是函数,这个函数就是回调函数
func anonymousFunc() {
arr :=[]float64{9,8,7,6,5,4,3,2,1,0}
filterSlice(arr, func(f float64) string {
return fmt.Sprint(f)
})
}