最近看到了一个没有见过的东西,函数柯里化,然后简单学习了一下这玩意,这里记录一下

本文主要参考掘金的一篇文章:「前端进阶」彻底弄懂函数柯里化 ,并使用Golang代替文中的JavaScript(貌似Golang函数柯里化相关的资料比较少)

什么是函数柯里化

在计算机科学中,柯里化(英语:Currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

举个简单的例子,函数foo(a, b, c int)的作用是返回a+b+c

func main() {
    fmt.Println(foo(1, 2, 3)) // 6
}

func foo(a, b, c int) int {
    return a + b + c
}

将这个函数柯里化之后,调用过程就变成fooCurry(1)(2)(3)

func main() {
    fmt.Println(foo(1, 2, 3)) // 6
    fmt.Println(fooCurry(1)(2)(3)) // 6
}

func foo(a, b, c int) int {
    return a + b + c
}

func fooCurry(a int) func(int) func(int) int {
    return func(b int) func(int) int {
        return func(c int) int {
            return a + b + c
        }
    }
}

foo(1,2,3)fooCurry(1)(2)(3),就叫函数柯里化

有什么用

乍一看,这特么,就是来捣乱的,柯里化就是把简单问题复杂化,但实际上,在某些特定的场景下,柯里化的函数使用起来会更加的方便,因为在将函数复杂化的同时,也给函数带来了更多的自由度,柯里化本质上是降低通用性,提高适用性。

这里举个例子,我们工作中会遇到各种需要通过正则检验的需求,比如校验电话号码、校验邮箱等 这时我们会封装一个通用函数checkByRegExp,接收两个参数,校验的正则对象和待校验的字符串:

func main() {
    mailPattern := `^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z]\.){1,4}[a-z]{2,4}$`
    phonePattern := `^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$`
    fmt.Println(checkByRegExp(mailPattern, "kakkk@live.com"))
    fmt.Println(checkByRegExp(mailPattern, "kakkk_live.com"))
    fmt.Println(checkByRegExp(phonePattern, "13800138000"))
    fmt.Println(checkByRegExp(phonePattern, "10086"))
}

func checkByRegExp(exp, str string) bool {
    match, _ := regexp.MatchString(exp, str)
    return match
}

如此一来,每次都需要传入一个正则(虽然可以定义常量),依旧显得冗余,因此,讲这个函数柯里化之后,我们可以定义一个函数checkMail := checkByRegExpCurry(mailPattern),用于校验邮箱,同理也可以定义校验手机号的函数

func main() {
    mailPattern := `^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z]\.){1,4}[a-z]{2,4}$`
    phonePattern := `^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$`
    checkMail := checkByRegExpCurry(mailPattern)
    checkPhone := checkByRegExpCurry(phonePattern)
    fmt.Println(checkMail("kakkk@live.com"))
    fmt.Println(checkMail("kakkk_live.com"))
    fmt.Println(checkPhone("13800138000"))
    fmt.Println(checkPhone("10086"))
}

func checkByRegExpCurry(exp string) func(string) bool {
    return func(str string) bool {
        match, _ := regexp.MatchString(exp, str)
        return match
    }
}

以上便是函数柯里化的一些简单的应用

然后就,没了,就这样吧

最后修改:2022 年 11 月 22 日
如果觉得我的文章对你有用,请随意赞赏