Swift中的函数式编程

一. 背景简介

  • 最近很多同学问关于ReactiveCocoa的问题, 所有打算写一个相关系列的文章,当然目前iOS主流编程语言正在向Swift转变,我会直接写RxSwift
  • 但是在自己准备下手的时候,发现如果能够理解函数式编程,对于后面理解响应式编程会很有帮助。
  • 同时Swift也是支持函数式编程的,因此打算先写一个函数式编程系列,后续再更新RxSwift
  • 如果对该系列有兴趣, 欢迎点击关注.

二. 需求的解决和思考?

  • 我们从一个示例程序说起
  • 示例:
    • 有一个数组, 数组中存放很多数字
    • 需求: 从数组中帅选出所有的偶数
// 定义数组(当然其他数字也可以)
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]

// 解决方案一:
var evens = [Int]()
for n in numbers {
    if n % 2 == 0 {
        evens.append(n)
    }
}

print(evens)
  • 方案解决了问题, 但是是否有缺陷呢?
    • 如果我希望得到所有的奇数应该怎么办?
    • 对! 复制一份, 或者直接在循环中判断.
    • 那么, 如果我想获得3的倍数, 4的倍数, 5的倍数数字呢? 复制多份? 显然并不合理.
    • 对! 扩展性非常的差!
  • 其实Swift提供了一个非常简单的API, 你可以根据自己的需要获取想要的数字.
    • 代码如下:
// 解决方案二:
let evens1 = numbers.filter { (num : Int) -> Bool in
    return num % 2 == 0
}
  • 方法的解析
    • filter接受一个闭包参数
    • 闭包本身有一个Int类型参数, 表示数组中的数字
    • 返回值是一个Bool类型. 用于过滤符合条件的数字
    • 当满足条件时, 就会将满足条件的数字放入到数组中
  • 这样做有什么好处?
    • 如果我选择获取奇数, 只需要将==改成!=
    • 如果我希望获取3/4/5的倍数, 只需要改变2
  • 甚至我们的代码还可以这样写:
    • Swift闭包的简单写法而已, $0表示用于获取第一个闭包参数
    • 不熟练可以暂时忽略这种写法
let evens2 = numbers.filter { $0 % 2 == 0 }

三. 什么是函数式编程?

  • 什么是函数式编程呢?
    • 函数式编程其实是一种编程思想, 代码写出来只是它的表现形式.
    • 在面向对象的编程思想中, 我们将要解决的一个个问题, 抽象成一个个类, 通过给类定义属性和方法, 让类帮助我们解决需要处理的问题.(其实面向对象也叫命令式编程, 就像给对象下一个个命令)
    • 而在函数式编程中, 我们则通过函数描述我们要解决的问题, 以及解决问题需要怎样的方案.
    • 函数本身可以作为变量, 作为参数, 作为返回值(这样说有一点抽象, 下面的解决方案中就是将函数作为函数的参数)

四. 示例程序分析

  • 面向对象的思考
    • 我现在要对一个数组进行处理, 我可以封装一个用于处理数组各种情况的工具类
    • 工具类中我提供下面几个方法
    • 1> 获取该数组所有的偶数
    • 2> 获取该数组所有的奇数
    • 3> 获取数组中其他数字
    • 当然你也可以让调用方法的时候多传递几个参数, 来确定我获取的到底是什么, 以便于让内部进行处理.
    • 但是工具类不可能考虑到各种情况, 另外到底要对数组进行怎样的处理, 其实调用者最清楚.
    • 那么为何不让调用者把要做怎样的操作给我传递过来呢?
  • 函数式编程的思考
    • 如果系统没有filter函数, 我们可以自己给Array扩充一个这样的函数
    • 封装一个函数, 函数的参数是一个对数组中数字的操作.
    • 这个数字到底是 %2 %3 %4, 将这样的操作传递进去
    • 既然是一个操作, 操作本身就是一个函数
    • 所有, 函数的参数是一个函数.(没错, 让函数作为函数的操作)
    • 代码如下:
// 给系统Array扩充函数
extension Array {
    func myOwnFilter(oprationFunc : (Int) -> Bool) -> [Int] {
        var tempArray = [Int]()

        for item in self {
            if oprationFunc(item as! Int) {
                tempArray.append(item as! Int)
            }
        }

        return tempArray
    }
}

// 用自己的函数解决问题
let evens3 = numbers.myOwnFilter { (num : Int) -> Bool in
    return num % 2 == 0
}
  • 代码解析:

    • 扩充的函数要求传递的是一个闭包, 闭包其实就是一个特殊的函数. 因此, 扩充的函数传递的是另外一个函数
    • 在扩充的函数中我们通过传递的函数来判断数字是否符合需求, 符合需求, 则加入数组中.
    • 这样我们就可以根据用户自定义的需求来过滤需要的数字了.
  • 如果我们的写的更有扩充性, 可以使用泛型

    • 比如: 获取字符串数组中包含"w"的字符串
    • 这个时候需要这样来修改我的函数
// Array扩充方法
extension Array {
    func myOwnFilter(oprationFunc : (Element) -> Bool) -> [Element] {
        var tempArray = [Element]()

        for item in self {
            if oprationFunc(item) {
                tempArray.append(item)
            }
        }

        return tempArray
    }
}

// 获取所有的偶数
let evens3 = numbers.myOwnFilter { (num : Int) -> Bool in
    return num % 2 == 0
}

// 获取所有带"w"的字符串
let strs = ["why", "lmj", "lnj", "yz", "wff", "sws"]
strs.myOwnFilter { (str : String) -> Bool in
    return str.containsString("w")
}

五. 函数式编程有什么用?

  • 函数式编程最早诞生于1958年, 在Lisp语言使用.
  • Lisp是什么?
    • Lisp有各种神奇的传说, 比如天才程序员通常使用Lisp, 比如用其他语言实现一个功能需要上千行的代码. 用Lisp只需要少许的代码.
    • Lisp目前并没有流行起来, 这可以说不是一门编程语言, 而是一门数学课.
    • Lisp被应用比较广泛的场景还是在人工智能中
  • 石器时代的函数式编程, 是否有学习的必要呢?
    • 其实目前非常火的语言包括Python、Ruby、Javascript, 对函数式编程的支持都很强, 就连java、PHP都有加入匿名函数(本质也是一种函数式编程)
    • 而2014发布的Swift, 就以支持函数式编程作为一大特点.
    • 函数式编程是否会成为下一个主流的编程范式, 我们不得而知. 但是未来的程序员必然得或多或少懂一点函数式编程. 才能写出更优秀的代码.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容