匿名函数就是没有定义函数名称的函数。我们可以在函数内部定义匿名函数,也叫函数嵌套。
匿名函数可以直接被调用,也可以赋值给变量、作为参数或返回值。比如:
func main(){
func(s string){ //直接被调用
println(s)
}("hello gopher!!!")
/*
func(s string){ //未被调用
println(s)
}
*/
}
func main(){
hi := func(s string){ //赋值给变量
println(s)
}
hi("hello gopher!!!")
}
func test(f func(string)){
f("hello gopher!!!")
}
func main(){
hi := func(s string){
println(s)
}
test(hi) //作为参数
}
func test()func(string){
hi := func(s string){ //作为返回值
println(s)
}
return hi
}
func main(){
f := test()
f("hello gopher!!!")
}
普通函数和匿名函数都可以作为结构体的字段,比如:
{
type calc struct{
mul func(x,y int)int
}
x := calc{
mul: func(x,y int)int{
return (x*y)
},
}
println(x.mul(2,3))
}
也可以经channel(通道)传递,比如:
{
c := make(chan func(int, int)int, 2)
c <- func(x,y int) int {return x + y}
println((<-c)(2,3))
}
闭包(closure)
闭包是指在上下文中引用了自由变量(未绑定到特定对象)的代码块(函数),或者说是代码块(函数)与和引用环境的组合体。比如:
func intSeq()func()int{
i := 0
println(&i)
return func()int{
i += 1
println(&i,i)
return i
}
}
func main(){
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
newInt := intSeq()
fmt.Println(newInt())
}
输出:
0xc42000a320
0xc42000a320 1
1
0xc42000a320 2
2
0xc42000a320 3
3
0xc42007a010
0xc42007a010 1
1
因为闭包是通过指针引用环境变量,那么就会导致该变量的生命周期
变长,甚至被分配到堆内存。如果多个匿名函数引用同一个环境变量,会让事情变得更加复杂,比如:
func test()[]func(){
var s []func()
for i:= 0;i < 3;i++{
s = append(s, func(){
println(&i , i)
})
}
return s
}
func main(){
funcSlice := test()
for _ , f := range funcSlice{
f()
}
}
输出:
0xc42000a320 3
0xc42000a320 3
0xc42000a320 3
解决方法就是每次用不同的环境变量或参数赋值,比如修改后的test函数:
func test()[]func(){
var s []func()
for i:= 0;i < 3;i++{
x := i
s = append(s, func(){
println(&x , x)
})
}
return s
}
闭包在不用传递参数的情况下就可以读取和修改环境变量,当然我们是要为这种遍历付出代价的,所以日常开发中,在高并发服务
的场景下建议慎用,除非你明确你的需求必须这样做。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。