本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
Golang函数式编程深入分析实例
codesky · 140浏览 · 发布于2023-01-10 +关注

习惯与函数式编程语言的开发者,会认为for循环和if判断语句是冗长的代码,通过使用map和filter处理集合元素让代码更可读。本文介绍Go闭包实现集合转换和过滤功能

定义集合功能函数

首先定义用于测试的结构体WorkWith:

// WorkWith is the struct we'll
// be implementing collections for
type WorkWith struct {
    Data    string
    Version int
}

针对该结构体定义filter和map函数:

// 基于判断函数过滤集合,返回符合条件的集合元素
func Filter(ws []WorkWith, f func(w WorkWith) bool) []WorkWith {
    // depending on results, smaller size for result
    // is len == 0
    result := make([]WorkWith, 0)
    for _, w := range ws {
        if f(w) {
            result = append(result, w)
        }
    }
    return result
}
// 基于转换函数转换集合元素,返回集合的元素为转换后的元素
func Map(ws []WorkWith, f func(w WorkWith) WorkWith) []WorkWith {
    // the result should always be the same
    // length
    result := make([]WorkWith, len(ws))
    for pos, w := range ws {
        newW := f(w)
        result[pos] = newW
    }
    return result
}

实现具体功能函数

import "strings"
// LowerCaseData does a ToLower to the
// Data string of a WorkWith
func LowerCaseData(w WorkWith) WorkWith {
    w.Data = strings.ToLower(w.Data)
    return w
}
// IncrementVersion increments a WorkWiths
// Version
func IncrementVersion(w WorkWith) WorkWith {
    w.Version++
    return w
}
// OldVersion returns a closures
// that validates the version is greater than
// the specified amount
func OldVersion(v int) func(w WorkWith) bool {
    return func(w WorkWith) bool {
        return w.Version >= v
    }
}

上面定义了三个函数,LowerCaseData修改WorkWith中Data值为小写形式,IncrementVersion让WorkWith中版本增加1,OldVersion基于参数过滤版本。

测试集合功能

定义测试用例文件:

import (
    "fmt"
    "testing"
)
func TestMap(t *testing.T) {
    ws := []WorkWith{
        {"Example", 1},
        {"Example 2", 2},
    }
    fmt.Printf("Initial list: %#v\n", ws)
    // first lower case the list
    ws = Map(ws, LowerCaseData)
    fmt.Printf("After LowerCaseData Map: %#v\n", ws)
    // next increment all versions
    ws = Map(ws, IncrementVersion)
    fmt.Printf("After IncrementVersion Map: %#v\n", ws)
    // lastly remove all versions older than 3
    ws = Filter(ws, OldVersion(3))
    fmt.Printf("After OldVersion Filter: %#v\n", ws)
}

运行 go test . -v

输出结果如下:

Initial list: []collections.WorkWith{collections.WorkWith{Data:"Example", Version:1}, collections.WorkWith{Data:"Example 2", Version:2}}

After LowerCaseData Map: []collections.WorkWith{collections.WorkWith{Data:"example", Version:1}, collections.WorkWith{Data:"example 2", Version:2}}

After IncrementVersion Map: []collections.WorkWith{collections.WorkWith{Data:"example", Version:2}, collections.WorkWith{Data:"example 2", Version:3}}

After OldVersion Filter: []collections.WorkWith{collections.WorkWith{Data:"example 2", Version:3}}

上面示例中,我们注意到函数都没有返回任何error对象,这遵循函数式编程思想,尽可能让函数纯粹:不修改原集合元素,即对原集合无副作用,而是生成新的集合。如果需要对集合应用多个功能,那么这种模式能够省去很多麻烦,并且测试也很简单。我们还可以将映射和过滤器链接在一起,让代码更简洁可读。

ws := []WorkWith{
    {"Example", 1},
    {"Example 2", 2},
}
fmt.Printf("Initial list: %#v\n", ws)
result := Filter(Map(Map(ws, LowerCaseData), IncrementVersion), OldVersion(3))
fmt.Printf("After OldVersion Filter: %#v\n", result)

如果功能函数定义为集合类型的方法,并返回集合类型,则上述代码会更优雅。

泛型实现

上面代码仅能在特定类型上使用,我们自然想实现泛型函数,下面通过一个简单示例进行说明:

func map2[T, U any](data []T, f func(T) U) []U {
    res := make([]U, 0, len(data))
    for _, e := range data {
        res = append(res, f(e))
    }
    return res
}

该函数接收类型T,转换后返回类型U,当然两者类型也可以一样。下面测试函数功能:

// 字符串转大写
words := []string{"war", "cup", "water", "tree", "storm"}
result := map2(words, func(s string) string {
    return strings.ToUpper(s)
})
fmt.Println(result)
// 生成原集合元素的平方集合
fmt.Println("-------------------")
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
squares := map2(numbers, func(n int) int {
    return n * n
})
fmt.Println(squares)
// 数值转为字符串
fmt.Println("-------------------")
as_strings := map2(numbers, func(n int) string {
    return strconv.Itoa(n)
})
fmt.Printf("%q", as_strings)


相关推荐

PHP实现部分字符隐藏

沙雕mars · 1325浏览 · 2019-04-28 09:47:56
Java中ArrayList和LinkedList区别

kenrry1992 · 908浏览 · 2019-05-08 21:14:54
Tomcat 下载及安装配置

manongba · 970浏览 · 2019-05-13 21:03:56
JAVA变量介绍

manongba · 962浏览 · 2019-05-13 21:05:52
什么是SpringBoot

iamitnan · 1086浏览 · 2019-05-14 22:20:36
加载中

0评论

评论
分类专栏
小鸟云服务器
扫码进入手机网页