GO编程模式学习笔记系列为学习陈皓的GO编程模式系列文章记录与心得。
原文链接:GO编程模式:MAP-REDUCE
Map
func MapStrToStr(arr []string, fn func(s string) string) []string { var newArray = []string{} for _, it := range arr { newArray = append(newArray, fn(it)) } return newArray } var list = []string{"Hao", "Chen", "MegaEase"} x := MapStrToStr(list, func(s string) string { return strings.ToUpper(s) }) fmt.Printf("%v\n", x) //["HAO", "CHEN", "MEGAEASE"]
MapStrToInt将如何从一个string变成另外string的实现交给了调用方。可以是转换为大写或者小写,甚至可以不转换返回原来字符串。
Map的模式在一个过程中反复需要同样签名的函数的时候能简化代码。实际上传入map的函数可以认为是一个接口。如果一个遍历过程传一个接口更合适,就可以考虑使用map方式简化代码。
Reduce
func Reduce(arr []string, fn func(s string) int) int { sum := 0 for _, it := range arr { sum += fn(it) } return sum } var list = []string{"Hao", "Chen", "MegaEase"} x := Reduce(list, func(s string) int { return len(s) }) fmt.Printf("%v\n", x) // 15
Reduce适合把一个集合变成一个标量,比如计算长度和,平均数等统计值。
Filter
func Filter(arr []int, fn func(n int) bool) []int { var newArray = []int{} for _, it := range arr { if fn(it) { newArray = append(newArray, it) } } return newArray } var intset = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} out := Filter(intset, func(n int) bool { return n%2 == 1 }) fmt.Printf("%v\n", out) out = Filter(intset, func(n int) bool { return n > 5 }) fmt.Printf("%v\n", out)
Filter是对单个元素的处理。
Map-Filter-Reduce组合起来是一个模式,可以用一张图表示:
Map/Reduce/Filter只是一种控制逻辑,真正的业务逻辑是在传给他们的数据和那个函数来定义的。是的,这是一个很经典的“业务逻辑”和“控制逻辑”分离解耦的编程模式。
泛型Map-Filter-Reduce,太复杂了不学了,不如使用代码生成手段。
以下引用了作者和网友对这个模式的理解:
在全世界范围内,有大量的程序员都在问Go语言官方什么时候在标准库中支持 Map/Reduce,Rob Pike说,这种东西难写吗?还要我们官方来帮你们写么?这种代码我多少年前就写过了,但是,我从来一次都没有用过,我还是喜欢用“For循环”,我觉得你最好也跟我一起用 “For循环”。
评论引用:
for 循环相比之下,一个问题是,思考的方式低了一个层级。另一方面,for 循环能做更多奇奇怪怪的事情,所以语义可以很复杂。
而 map / filter / reduce 是相当好理解的:先变换,再过滤,最后总结。不管你每一步的操作多么复杂,其复杂性都被分离开了,而不会纠缠在一起,让人迷失方向。