Swift中的函數(shù)式編程

一. 背景簡介

  • 最近很多同學(xué)問關(guān)于ReactiveCocoa的問題谴咸, 所有打算寫一個相關(guān)系列的文章,當(dāng)然目前iOS主流編程語言正在向Swift轉(zhuǎn)變骗露,我會直接寫RxSwift岭佳。
  • 但是在自己準(zhǔn)備下手的時候,發(fā)現(xiàn)如果能夠理解函數(shù)式編程萧锉,對于后面理解響應(yīng)式編程會很有幫助珊随。
  • 同時Swift也是支持函數(shù)式編程的,因此打算先寫一個函數(shù)式編程系列柿隙,后續(xù)再更新RxSwift
  • 如果對該系列有興趣, 歡迎點擊關(guān)注.

二. 需求的解決和思考叶洞?

  • 我們從一個示例程序說起
  • 示例:
    • 有一個數(shù)組, 數(shù)組中存放很多數(shù)字
    • 需求: 從數(shù)組中帥選出所有的偶數(shù)
// 定義數(shù)組(當(dāng)然其他數(shù)字也可以)
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)
  • 方案解決了問題, 但是是否有缺陷呢?
    • 如果我希望得到所有的奇數(shù)應(yīng)該怎么辦?
    • 對! 復(fù)制一份, 或者直接在循環(huán)中判斷.
    • 那么, 如果我想獲得3的倍數(shù), 4的倍數(shù), 5的倍數(shù)數(shù)字呢? 復(fù)制多份? 顯然并不合理.
    • 對! 擴展性非常的差!
  • 其實Swift提供了一個非常簡單的API, 你可以根據(jù)自己的需要獲取想要的數(shù)字.
    • 代碼如下:
// 解決方案二:
let evens1 = numbers.filter { (num : Int) -> Bool in
    return num % 2 == 0
}
  • 方法的解析
    • filter接受一個閉包參數(shù)
    • 閉包本身有一個Int類型參數(shù), 表示數(shù)組中的數(shù)字
    • 返回值是一個Bool類型. 用于過濾符合條件的數(shù)字
    • 當(dāng)滿足條件時, 就會將滿足條件的數(shù)字放入到數(shù)組中
  • 這樣做有什么好處?
    • 如果我選擇獲取奇數(shù), 只需要將==改成!=
    • 如果我希望獲取3/4/5的倍數(shù), 只需要改變2
  • 甚至我們的代碼還可以這樣寫:
    • Swift閉包的簡單寫法而已, $0表示用于獲取第一個閉包參數(shù)
    • 不熟練可以暫時忽略這種寫法
let evens2 = numbers.filter { $0 % 2 == 0 }

三. 什么是函數(shù)式編程?

  • 什么是函數(shù)式編程呢?
    • 函數(shù)式編程其實是一種編程思想, 代碼寫出來只是它的表現(xiàn)形式.
    • 在面向?qū)ο蟮木幊趟枷胫? 我們將要解決的一個個問題, 抽象成一個個類, 通過給類定義屬性和方法, 讓類幫助我們解決需要處理的問題.(其實面向?qū)ο笠步忻钍骄幊? 就像給對象下一個個命令)
    • 而在函數(shù)式編程中, 我們則通過函數(shù)描述我們要解決的問題, 以及解決問題需要怎樣的方案.
    • 函數(shù)本身可以作為變量, 作為參數(shù), 作為返回值(這樣說有一點抽象, 下面的解決方案中就是將函數(shù)作為函數(shù)的參數(shù))

四. 示例程序分析

  • 面向?qū)ο蟮乃伎?
    • 我現(xiàn)在要對一個數(shù)組進行處理, 我可以封裝一個用于處理數(shù)組各種情況的工具類
    • 工具類中我提供下面幾個方法
    • 1> 獲取該數(shù)組所有的偶數(shù)
    • 2> 獲取該數(shù)組所有的奇數(shù)
    • 3> 獲取數(shù)組中其他數(shù)字
    • 當(dāng)然你也可以讓調(diào)用方法的時候多傳遞幾個參數(shù), 來確定我獲取的到底是什么, 以便于讓內(nèi)部進行處理.
    • 但是工具類不可能考慮到各種情況, 另外到底要對數(shù)組進行怎樣的處理, 其實調(diào)用者最清楚.
    • 那么為何不讓調(diào)用者把要做怎樣的操作給我傳遞過來呢?
  • 函數(shù)式編程的思考
    • 如果系統(tǒng)沒有filter函數(shù), 我們可以自己給Array擴充一個這樣的函數(shù)
    • 封裝一個函數(shù), 函數(shù)的參數(shù)是一個對數(shù)組中數(shù)字的操作.
    • 這個數(shù)字到底是 %2 %3 %4, 將這樣的操作傳遞進去
    • 既然是一個操作, 操作本身就是一個函數(shù)
    • 所有, 函數(shù)的參數(shù)是一個函數(shù).(沒錯, 讓函數(shù)作為函數(shù)的操作)
    • 代碼如下:
// 給系統(tǒng)Array擴充函數(shù)
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
    }
}

// 用自己的函數(shù)解決問題
let evens3 = numbers.myOwnFilter { (num : Int) -> Bool in
    return num % 2 == 0
}
  • 代碼解析:

    • 擴充的函數(shù)要求傳遞的是一個閉包, 閉包其實就是一個特殊的函數(shù). 因此, 擴充的函數(shù)傳遞的是另外一個函數(shù)
    • 在擴充的函數(shù)中我們通過傳遞的函數(shù)來判斷數(shù)字是否符合需求, 符合需求, 則加入數(shù)組中.
    • 這樣我們就可以根據(jù)用戶自定義的需求來過濾需要的數(shù)字了.
  • 如果我們的寫的更有擴充性, 可以使用泛型

    • 比如: 獲取字符串?dāng)?shù)組中包含"w"的字符串
    • 這個時候需要這樣來修改我的函數(shù)
// Array擴充方法
extension Array {
    func myOwnFilter(oprationFunc : (Element) -> Bool) -> [Element] {
        var tempArray = [Element]()

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

        return tempArray
    }
}

// 獲取所有的偶數(shù)
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")
}

五. 函數(shù)式編程有什么用?

  • 函數(shù)式編程最早誕生于1958年, 在Lisp語言使用.
  • Lisp是什么?
    • Lisp有各種神奇的傳說, 比如天才程序員通常使用Lisp, 比如用其他語言實現(xiàn)一個功能需要上千行的代碼. 用Lisp只需要少許的代碼.
    • Lisp目前并沒有流行起來, 這可以說不是一門編程語言, 而是一門數(shù)學(xué)課.
    • Lisp被應(yīng)用比較廣泛的場景還是在人工智能中
  • 石器時代的函數(shù)式編程, 是否有學(xué)習(xí)的必要呢?
    • 其實目前非常火的語言包括Python禀崖、Ruby衩辟、Javascript, 對函數(shù)式編程的支持都很強, 就連java俩莽、PHP都有加入匿名函數(shù)(本質(zhì)也是一種函數(shù)式編程)
    • 而2014發(fā)布的Swift, 就以支持函數(shù)式編程作為一大特點.
    • 函數(shù)式編程是否會成為下一個主流的編程范式, 我們不得而知. 但是未來的程序員必然得或多或少懂一點函數(shù)式編程. 才能寫出更優(yōu)秀的代碼.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末费韭,一起剝皮案震驚了整個濱河市皆愉,隨后出現(xiàn)的幾起案子闯参,更是在濱河造成了極大的恐慌崩侠,老刑警劉巖圈澈,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咱揍,死亡現(xiàn)場離奇詭異节预,居然都是意外死亡仅财,警方通過查閱死者的電腦和手機狈究,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盏求,“玉大人抖锥,你說我怎么就攤上這事》缋” “怎么了宁改?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長魂莫。 經(jīng)常有香客問我还蹲,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任谜喊,我火速辦了婚禮潭兽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斗遏。我一直安慰自己山卦,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布诵次。 她就那樣靜靜地躺著账蓉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逾一。 梳的紋絲不亂的頭發(fā)上铸本,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音遵堵,去河邊找鬼箱玷。 笑死,一個胖子當(dāng)著我的面吹牛陌宿,可吹牛的內(nèi)容都是我干的锡足。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼壳坪,長吁一口氣:“原來是場噩夢啊……” “哼舶得!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弥虐,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤扩灯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后霜瘪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡惧磺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年颖对,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磨隘。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡缤底,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出番捂,到底是詐尸還是另有隱情个唧,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布设预,位于F島的核電站徙歼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜魄梯,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一桨螺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酿秸,春花似錦灭翔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稀蟋,卻和暖如春煌张,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糊治。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工唱矛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人井辜。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓绎谦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親粥脚。 傳聞我的和親對象是個殘疾皇子窃肠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容