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
118 1
|
Python
【Python函数式编程】——偏函数(Partial function)
 Python的 functools 模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。
194 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.
712 0
|
Go 定位技术
learn go anonymous function
package main // 参考文档: // https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/06.
626 0
|
13天前
|
中间件 Docker Python
【Azure Function】FTP上传了Python Function文件后,无法在门户页面加载函数的问题
通过FTP上传Python Function至Azure云后,出现函数列表无法加载的问题。经排查,发现是由于`requirements.txt`中的依赖包未被正确安装。解决方法为:在本地安装依赖包到`.python_packages/lib/site-packages`目录,再将该目录内容上传至云上的`wwwroot`目录,并重启应用。最终成功加载函数列表。
|
2月前
|
JavaScript
箭头函数与普通函数(function)的区别
箭头函数是ES6引入的新特性,与传统函数相比,它有更简洁的语法,且没有自己的this、arguments、super或new.target绑定,而是继承自外层作用域。箭头函数不适用于构造函数,不能使用new关键字调用。
|
2月前
|
数据可视化 开发者 索引
详解Wireshark LUA插件函数:function p_myproto.dissector(buffer, pinfo, tree)
在 Wireshark 中,LUA 插件通过 `function p_myproto.dissector(buffer, pinfo, tree)` 扩展协议解析能力,解析自定义应用层协议。参数 `buffer` 是 `PacketBuffer` 类型,表示原始数据包内容;`pinfo` 是 `ProtoInfo` 类型,包含数据包元信息(如 IP 地址、协议类型等);`tree` 是
79 1
|
2月前
|
JavaScript
箭头函数与普通函数(function)的区别
箭头函数是ES6引入的新语法,相比传统函数表达式更简洁,且没有自己的this、arguments、super或new.target绑定,而是继承自外层作用域。这使得箭头函数在处理回调和闭包时更加灵活方便。
|
2月前
|
C++ 容器
函数对象包装器function和bind机制
函数对象包装器function和bind机制
21 0

热门文章

最新文章