函数式编程
虽然go不推崇函数式编程,但是局部使用这种编程范式可以得到更好优化,更加简洁的代码。
\1. 柯里化函数
将接受多个参数的函数,转变成只接受一个参数的函数,返回一个接受了剩下参数并返回相应结果的技术。
这个技术利用了函数的两个性质,在函数中定义,通过返回值返回,闭包。
package main
import "fmt"
func times(x, y int) int {
return x * y
}
func partialTimes(x int) func(int) int {
return func(y int) int {
return times(x, y)
}
}
func main() {
timesTwo := partialTimes(2)
timesThree := partialTimes(3)
timesFour := partialTimes(4)
fmt.Println(timesTwo(5))
fmt.Println(timesThree(5))
fmt.Println(timesFour(5))
}
\2. 函子
函子需要满足两个条件: 函子本身是一个容器类型,以Go语言为例,这个容器可以是切 片、map甚至channel; 该容器类型需要实现一个方法,该方法接受一个函数类型参数, 并在容器的每个元素上应用那个函数,得到一个新函子,原函子 容器内部的元素值不受影响。
package main
import (
"fmt"
)
type IntSliceFunctor interface {
Fmap(fn func(int) int) IntSliceFunctor
}
type intSliceFunctorImpl struct {
ints []int
}
func (isf intSliceFunctorImpl) Fmap(fn func(int) int) IntSliceFunctor {
newInts := make([]int, len(isf.ints))
for i, elt := range isf.ints {
retInt := fn(elt)
newInts[i] = retInt
}
return intSliceFunctorImpl{ints: newInts}
}
func NewIntSliceFunctor(slice []int) IntSliceFunctor { return intSliceFunctorImpl{ints: slice} }
func main() {
// 原切片
intSlice := []int{1, 2, 3, 4}
fmt.Printf("init a functor from int slice: %#v\n", intSlice)
f := NewIntSliceFunctor(intSlice)
fmt.Printf("original functor: %+v\n", f)
mapperFunc1 := func(i int) int { return i + 10 }
mapped1 := f.Fmap(mapperFunc1)
fmt.Printf("mapped functor1: %+v\n", mapped1)
mapperFunc2 := func(i int) int { return i * 3 }
mapped2 := mapped1.Fmap(mapperFunc2)
fmt.Printf("mapped functor2: %+v\n", mapped2)
fmt.Printf("original functor: %+v\n", f) // 原函子没有改变
fmt.Printf("composite functor: %+v\n", f.Fmap(mapperFunc1).Fmap(mapperFunc2))
}
函子非常适合用来对容器集合元素进行批量同构处理,而且代码也比每次都对容器中的元素进行循环处理要优雅、简洁许多。但要想在Go中发挥函子的最大效能,还需要Go对泛型提供支持,否则我们就需要为每一种容器类型都实现一套对应的Functor机制。
\3. CPS风格
函数式编程有一种被称为延续传递式 (Continuation-passing Style,CPS)的编程风格可以充分运用函数作 为”一等公民”的特质。 在CPS风格中,函数是不允许有返回值的。一个函数A应该将其想返回的值显式传给一个continuation函数(一般接受一个参数),而这 个continuation函数自身是函数A的一个参数。
package main
import(
"fmt"
)
func factorial(n int, f func(int)) {
if n == 1 {
f(1) // 基本情况
} else {
factorial(n-1, func(y int) { f(n * y) })
}
}
func main() {
factorial(5, func(y int) {
fmt.Printf("%d\n", y)
})
}