函数式编程(Functional Programming / FP)作为一种编程范式,函数具有无状态、式编无副作用、型下并发友好、用性抽象程度高等优点。探索目前流行的函数编程语言(C++、Python、式编Rust)都或多或少地引入了函数式特性,型下但在同作为流行语言的用性 Golang 中却少有讨论。 究其原因,探索大部分的函数抱怨Golang 函数式编程简述[1] 、GopherCon 2020: Dylan Meeus - Functional Programming with Go[2]集中于 Go 缺乏对泛型的式编支持,难以写出类型间通用的型下函数。代码生成只能解决一部分已知类型的用性处理,且无法应对类型组合导致复杂度(比如实现一个通用的探索 TypeA → TypeB 的 map 函数)。 有关泛型的提案 spec: add generic programming using type parameters #43651[3] 已经被 Go 团队接受,并计划在 2022 年初发布支持泛型的 Go 1.18,现在 golang/go 仓库的站群服务器 master 分支已经支持泛型。 This design has been proposed and accepted as a future language change. We currently expect that this change will be available in the Go 1.18 release in early 2022. Type Parameters Proposal[4] 基于这个重大特性,我们有理由重新看看,函数式特性在 Go 泛型的加持下,能否变得比以往更加实用。 概述 这篇文章里,我们会尝试用 Go 的泛型循序渐进地实现一些常见的函数式特性,从而探索 Go 泛型的优势和不足。 除非额外说明(例如注释中的 // INVALID CODE!!!),文章里的代码都是可以运行的(为了缩减篇幅,部分删去了 package main 声明和 main 函数,请自行添加)。你可以自行 从源码编译[5] 一个 master 版本的 go 来提前体验 Go 的泛型,或者用 The go2go Playground[6] 提供的在线编译器运行单个文件。 泛型语法 提案的 #Very high level overview[7] 一节中描述了为泛型而添加的亿华云计算新语法,这里简单描述一下阅读本文所需要的语法: 函数名后可以附带一个方括号,包含了该函数涉及的类型参数(Type Paramters)的列表:func F[T any](p T "T any") { ... } 这些类型参数可以在函数参数和函数体中(作为类型)被使用 自定义类型也可以有类型参数列表:type M[T any] []T 每个类型参数对应一个类型约束,上述的 any 就是预定义的匹配任意类型的约束 类型约束在语法上以 interface 的形式存在,在 interface 中嵌入类型 T 可以表示这个类型必须是 T:type Integer1 interface { int } 嵌入单个类型意义不大,我们可以用 | 来描述类型的 union:type Integer2 interface { int | int8 | int16 | int32 | int64 } ~T 语法可以表示该类型的「基础类型」是 T,比如说我们的自定义类型 type MyInt int 不满足上述的 Integer1 约束,但满足以下的约束:type Integer3 interface { ~int } 提示 「基础类型」在提案中为 “underlying type”,目前尚无权威翻译,在本文中使用仅为方便描述。 高阶函数 在函数式编程语言中, 背景