Go 函数式编程:Higher-order function

简介: Go 函数式编程:Higher-order function

在请求处理过程中,应用程序会接受和处理请求,然后返回响应结果。在该过程中,还存在一些通用的功能,例如:鉴权、监控、链路追踪。众多 RPC 框架会提供称之为 Middleware 或者 Interceptor 等概念,以可插拔的方式来支持上述谈到的众多功能。以 gRPC 为例,工作原理如图:

其服务端的接口如下所示:

func UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error)
func StreamServerInterceptor (srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error

可以看到,接口明确定义了输入参数,输出结果。如果我们要自己实现一个组件,需要支持使用者传入特定的配置,有没有什么办法可以做到呢?

答案是肯定的。

Higher-order function

在了解具体的解决方案之前,需要先了解一个概念叫Higher-order function(高阶函数)

高阶函数是指至少支持以下特定之一的函数:

  1. 将一个或多个函数作为参数(即过程参数),
  2. 返回函数作为其结果

第二点,正是需要的特性。以限流的 interceptor 为例,支持传入自定义的限流器。此时就需要定义一个以限流器为参数的高阶函数,然后返回的函数是框架需要的 Interceptor,并在 Interceptor 函数内使用传入的限流器判断是否需要限流。按照接口限流的 Interceptor 具体实现为:

type Limiter interface {
  Limit(key string) bool
}
func UnaryServerInterceptor(limiter Limiter) grpc.UnaryServerInterceptor {
  return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    if limiter.Limit(info.FullMethod) {
      return nil, status.Errorf(codes.ResourceExhausted, "%s is rejected by grpc_ratelimit middleware, please retry later.", info.FullMethod)
    }
    return handler(ctx, req)
  }
}
...

目前传入的参数是固定的,可以这么来实现。更进一步,如果使用比较复杂,除了当前已经确定的参数,可以预期以后会增加更多的参数。也就要求当前设计的接口需要有很好的扩展性。还有办法么?

答案同样是肯定的。

Functional Options

没有意外,利用的就是高阶函数的第一点,该编程模式有一个特定的名称:Functional Options。

首先为传入的参数定义结构体

type options struct {
    byMethod  bool
    byUser    bool
    byClientIP bool
}

其次,再定义一个函数类型:

type Option func(*Options)

再次,定义修改配置的一组函数

func ByMethod(m bool) Option {
    return func(o *options) {
        o.byMethod = m
    }
}
func ByUser(u bool) Option {
    return func(o *options) {
        o.byUser = u
    }
}
func ByClientIP(c bool) Option {
    return func(o *options) {
        o.byClientIP = c
    }
}

最后,修改提供的 Interceptor 为:

func UnaryServerInterceptor(limiter Limiter, opts ...Option) grpc.UnaryServerInterceptor {
  return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
        default := options {
            byMethod: true,
            byUser: false,
            byClientIP: false,
        }
        for _, opt := range opts {
            opt(&default)
        }
        ...
    return handler(ctx, req)
  }
}

如是,你就拥有了一个具有扩展性、支持自定义参数的 Interceptor。

最后

做个总结,谈个观点:

  1. 高阶函数,并不是属于哪一个特定的编程语言。其他语言如C++,同样支持类似的特性。
  2. 作为架构师需要了解实现细节么,答案是需要。否则,在特定环境下,拿什么来支撑设计所谓的扩展性呢。

本文作者 : cyningsun

本文地址https://www.cyningsun.com/07-19-2021/go-higher-order-function.html

版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!

# Golang

  1. 译|There Are No Reference Types in Go
  2. Go 语言没有引用类型,指针也与众不同
  3. 译|What “accept interfaces, return structs” means in Go
  4. 如何用好 Go interface
  5. 一个优雅的 LRU 缓存实现
目录
相关文章
|
7月前
|
Java API 容器
Java8函数式编程接口:Consumer、Supplier、Function、Predicate
Java8函数式编程接口:Consumer、Supplier、Function、Predicate
135 1
|
Python
【Python函数式编程】——偏函数(Partial function)
 Python的 functools 模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。
196 0
【Python函数式编程】——偏函数(Partial function)
|
Go
learn go function callback
package main // 参考文档: // https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/06.
716 0
|
Go 定位技术
learn go anonymous function
package main // 参考文档: // https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/06.
629 0
|
3天前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
32 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
23天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
37 7
|
23天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
23天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
99 71
|
22天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
102 67