Golang匿名函数与闭包

简介: Golang匿名函数与闭包

匿名函数


什么是匿名函数


没有名字的函数,由于函数中不可定义有名字的函数,所有出现匿名函数,匿名函数常使用于函数中定义函数


匿名函数的定义


func(参数) (返回值){
    函数体
}


其中参数、返回值视情况酌情加入


简单的示例


package mainimport "fmt"func f1(x, y int) int {    return x + y
}var f2 = func(x, y int) int {    return x * y
}func main() {
    fmt.Println(f1(2, 2))   // 4
    fmt.Println(f2(2, 2))   // 4}


f1:普通的函数有参数、返回值。直接使用f1()调用即可


f2:匿名函数,有参数,有返回值。变量f2,为函数类型,使用f2()可调用


闭包


闭包指的是一个函数和与其相关的引用环境组合而成的实体。闭包=函数+引用环境。示例如下


package mainimport "fmt"func main() {
    fmt.Println(f1()(1, 2)) 
}func f1() func(x int, y int) int {    return func(x, y int) int{        return x + y
    }
}// 3


可以简单理解为函数里面包含函数(多为匿名函数)


深入理解闭包


闭包常常与作用域之间的关系慎密,首先让我们回顾一下作用域,作用域的范围由上到下分为这几种:


  • 全局:


即全局均可调用,当在函数中调用修改后并不会直接影响


  • 函数作用域:


仅在此函数中进行有效


  • 代码块作用域:


仅在此代码块中有效,用完即释放。


且外部访问不到此变量(常量)


除全局外,二者均是相对的概念,不必过于拘泥。


生命周期


一旦进行嵌套的,很多朋友就会懵,那么我们进行几个case来尝试一下。如下


package mainimport "fmt"func f1() func(int) int {    var x int
    return func(y int) int {
        x += y        return x
    }
}func main() {
    f := f1()
    fmt.Println(f(11))
    fmt.Println(f(22))
    fmt.Println(f(33))
    fmt.Println(f(44))
    fmt.Println(f(55))
}// 11,33,66,110,165


变量f是一个函数并且它引用了其外部作用域中的x变量,此时f就是一个闭包。在f的生命周期内,变量x也一直有效。


package mainimport "fmt"func f2(x int) func(int) int {    return func(y int) int {
        x += y        return x
    }
}func main() {
    f := f2(20)
    fmt.Println(f(21))
    fmt.Println(f(22))
    fmt.Println(f(23))
    fmt.Println(f(24))
}


变量f是一个函数并且它引用了其外部作用域中的x变量,此时f就是一个闭包。在f的生命周期内,变量x也一直有效。


装饰器函数


学其他语言的同学,一定听说过甚至使用过装饰器。那让我们使用golang来实现装饰器的这个功能,如下:


package mainimport (    "fmt"
    "time")func Decorator(f func()) {
    fmt.Printf("The start Time: %s\n", time.Now())
    f()
    fmt.Printf("The end Time: %s\n", time.Now())
}func Hw() {
    fmt.Println("HelloWorld")
    time.Sleep(20 * time.Second)
}func main() {    //fmt.Println(f1()(1, 2))
    Decorator(Hw)
}


输入效果如下:


The start Time: 2020-11-17 19:24:23.969042 +0800 CST m=+0.000082415

helloWorld


The end Time: 2020-11-17 19:24:43.974545 +0800 CST m=+20.005388822


闭包其实并不复杂,只要牢记闭包=函数+引用环境(变量作用域)

目录
相关文章
|
Go
Go 语言使用 goroutine 运行闭包的“坑”
Go 语言使用 goroutine 运行闭包的“坑”
57 0
|
Serverless Go
Go语言闭包不打烊,让你长见识!
Go语言闭包不打烊,让你长见识!
47 0
|
3月前
|
存储 运维 安全
go语言中闭包与匿名函数是什么?
本文探讨了Go语言中的匿名函数与闭包。首先介绍了匿名函数的定义与使用方式,包括直接调用、赋值给变量以及作为全局变量的应用。接着深入解析了闭包的概念及其本质,强调闭包能实现状态保持,但也警告其不当使用可能导致复杂的内存管理和运维问题。通过示例展示了如何利用闭包实现累加器功能,并对比了使用结构体字段的方法。最后,通过一个并发场景的示例说明了闭包在Go中处理多协程安全访问共享数据的应用,展示了闭包结合锁机制确保数据一致性的方式。
|
12月前
|
缓存 Java Serverless
Golang中的闭包详解
Golang中的闭包详解
|
3月前
|
编译器 Go
Go语言中的闭包:封装数据与功能的强大工具
Go语言中的闭包:封装数据与功能的强大工具
|
5月前
|
Go
go的函数定义、递归、延迟、匿名、高阶、闭包
go的函数定义、递归、延迟、匿名、高阶、闭包
|
5月前
|
Go
Go语言进阶篇——浅谈函数中的闭包
Go语言进阶篇——浅谈函数中的闭包
|
6月前
|
Go C++
go 语言回调函数和闭包
go 语言回调函数和闭包
|
6月前
|
存储 编译器 Go
GO闭包实现原理(汇编级讲解)
函数闭包一点也不神秘,它就是函数和引用环境而组合的实体。在Go中,闭包在底层是一个结构体对象,它包含了函数指针与自由变量。Go编译器的逃逸分析机制,会将闭包对象分配至堆中,这样自由变量就不会随着函数栈的销毁而消失,它能依附着闭包实体而一直存在。因此,闭包使用的优缺点是很明显的:闭包能够避免使用全局变量,转而维持自由变量长期存储在内存之中;但是,这种隐式地持有自由变量,在使用不当时,会很容易造成内存浪费与泄露。附着闭包实体而一直存在。
78 0
GO闭包实现原理(汇编级讲解)
|
算法 Go 调度