匿名函数
Golang支持匿名函数,就是在定义函数时只有函数体没有函数名,并且函数可以赋值给变量,作为其他函数的参数进行传递;下面是一个匿名函数的例子:
package main
import "fmt"
func main() {
// 创建一个匿名函数并且赋值给一个变量
f := func(a,b int) int {
return a+b
}
// 调用匿名函数
fmt.Println(f(2,3))
}
使用匿名函数作为回调函数来获取到一个数组当中的一个最大值,如下:
import "fmt"
func main() {
vals := []int{2,6,12,1,3}
var maxVal int
for _,v := range vals{
//此处传入比较的具体值和函数
if !compare(maxVal,v, func(a, b int) bool {
return a>=b
}){
maxVal = v
}
}
fmt.Printf("The max value :%d",maxVal)
}
//比较这两个值
func compare(c,d int,f func(a, b int) bool) bool {
return f(c,d)
}
闭包
闭包就是匿名函数与其相关的引用环境组合而成的一个实体,可以在变量的作用域外继续调用这个变量;如下所示:
package main
import "fmt"
func main() {
fuc := f(10)
fmt.Println(fuc(10))
}
// 这个变量 i 的作用域在当前这个函数内,但是闭包会保存这个变量的值,到了真正调用这个闭包时使用,这就变相的延长了这个变量的作用域
func f(i int) func(j int) int {
//此次返回的这个函数就是闭包
return func(j int) int {
return i + j
}
}
在web框架beego的中间件中也是使用到了闭包来实现中间件的调用,下面是一个具体的例子
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// 定义了一个函数类型
type HandlerFunc func(resp http.ResponseWriter,req *http.Request)
// 该函数类型实现了 Handler 接口,所以就可以将跟它签名相同的方法也转化为 handler
func (h HandlerFunc) ServeHTTP(resp http.ResponseWriter,req *http.Request){
h(resp,req)
}
// Middleware middleware which add X-Request-ID header in the http request when not exist
func Middleware(skippers ...middleware.Skipper) func(http.Handler) http.Handler {
return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) {
rid := r.Header.Get(HeaderXRequestID)
if rid == "" {
rid = uuid.New().String()
r.Header.Set(HeaderXRequestID, rid)
}
w.Header().Set(HeaderXRequestID, rid)
//此处就是调用下一个 handler 的 ServeHTTP 方法
next.ServeHTTP(w, r)
}, skippers...)
}
// New make a middleware from fn which type is func(w http.ResponseWriter, r *http.Request, next http.Handler)
func New(fn func(http.ResponseWriter, *http.Request, http.Handler), skippers ...Skipper) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
// 此处将这个闭包转化为 HandlerFunc ,则这个闭包也实现了 Handler 接口,而其实现体就是这个闭包本身
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
for _, skipper := range skippers {
if skipper(r) {
next.ServeHTTP(w, r)
return
}
}
fn(w, r, next)
})
}
}
for i := len(mws) - 1; i >= 0; i-- {
if mws[i] == nil {
continue
}
// 此处就相当于一个链子一样,将所有的闭包函数链接起来,但是我感觉更像是闭包栈,比如,现在有三个闭包 A,B,C 首先进栈的是 C,然后将 C 作为参数传递给 B,然后再把 B 作为参数,将其传递给 A
// 在 A 的时候执行 A.ServeHTTP() 方法,此处除了执行 A 这个闭包本身的逻辑之外,还会再调用 next.ServeHTTP 而这个 next 就是作为参数传递给 A 的 B,依次类推
app.Server.Handler = mws[i](app.Server.Handler)
}
总结
现在发现很多很多设计模式中的类,都可以使用匿名函数进行代替