Swift # 柯裡化函數

來源:互聯網
上載者:User

標籤:

前言

  此次文章,講述的是Swift的一個新特性(柯裡化函數),可能很多iOS開發人員是第一次聽這個詞彙,包括我自己也是,自己也用了幾天時間才總結出來,希望能協助到各位咯,個人感覺偏向有開發經驗的碼友,如果零基礎的看懂,希望能給個贊,??!

如果喜歡我的文章,可以關注我,隨著後續不斷學習Swift中,陸續還會有更新ing....

 

什麼是柯裡化函數?

  柯裡化(Currying),又稱部分求值(Partial Evaluation),是一種函數式編程思想,就是把接受多個參數的函數轉換成接收一個單一參數(最初函數的第一個參數)的函數,並且返回一個接受餘下參數的新函數技術。

class Currying{    // uncurried:普通函數    // 接收多個參數的函數(與類相關的函數,統稱為方法,但是這裡就直接說函數了,方便理解)    func add(a: Int, b: Int, c: Int) -> Int{        println("\(a) + \(b) + \(c)")        return a + b + c    }     // curried:柯裡化函數    // 柯裡化函數,Swift中已經支援這樣的文法了,可以直接寫    func addCur(a: Int)(b: Int)(c: Int) -> Int{        println("\(a) + \(b) + \(c)")        return a + b + c    }}

 

如何定義柯裡化函數?

定義柯裡化函數:

柯裡化函數實現原理

class Currying{    /*** uncurried:普通函數 ***/    // 接收多個參數的函數    func add(a: Int, b: Int, c: Int) -> Int{        println("\(a) + \(b) + \(c)")        return a + b + c    }     /*** 手動實現柯裡化函數 ***/    // 把上面的函數轉換為柯裡化函數,首先轉成接收第一個參數a,並且返回接收餘下第一個參數b的新函數(採用閉包)    // 為了讓大家都能看懂,我幫你們拆解來看下    // (a: Int) : 參數    // (b:Int) -> (c: Int) -> Int : 函數傳回值(一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數)     // 定義一個接收參數a,並且返回一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數    func add(a: Int) -> (b:Int) -> (c: Int) -> Int{         // 一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數        return { (b:Int) -> (c: Int) -> Int in          // 返回一個接收餘下第一個參數c,並且有返回結果為Int類型的函數         return { (c: Int) -> Int in          return a + b + c;      註解: 這裡為什麼能使用參數a,b,c?           利用閉包的值捕獲特性,即使這些值範圍不在了,也可以捕獲到他們的值。           閉包會自動判斷捕獲的值是值拷貝還是值引用,如果修改了,就是值引用,否則值拷貝。            注意只有在閉包中才可以,a,b,c都在閉包中。            }        }    }     /*** curried: 系統內建的柯裡化函數 ***/    func addCur(a: Int)(b: Int)(c: Int) -> Int{        println("\(a) + \(b) + \(c)")        return a + b + c    }}

 

如何調用柯裡化函數

由於定義的是一個執行個體方法,因此調用需要依賴對象.

調用柯裡化函數:

 

// 建立柯裡化類的執行個體var curryInstance = Currying()/*** 調用手動實現的柯裡化函數 **/var r: Int = curryInstance.add(10)(b: 20)(c: 30)// 可能很多人都是第一次看這樣的調用,感覺有點不可思議。// 讓我們回顧下OC建立對象 [[Person alloc] init],這種寫法應該都見過吧,就是一下發送了兩個訊息,alloc返回一個執行個體,再用執行個體調用init初始化,上面也是一樣,一下調用多個函數,每次調用都會返回一個函數,然後再次調用這個返回的函數。 /***** 柯裡化函數分解調用 *****/// 讓我來幫你們拆解下,更容易看懂// curryInstance.add(10): 調用一個接收參數a,並且返回一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數// functionB: 一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數let functionB = curryInstance.add(10) // functionB(b: 20):調用一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數// functionC: 一個接收參數c,傳回值為Int類型的函數let functionC = functionB(b: 20) // functionC(c: 30): 調用一個接收參數c,傳回值為Int類型的函數// result: 函數的傳回值var res: Int = functionC(c: 30); // 這裡會有疑問?,為什麼不是調用curryInstance.add(a: 10),而是curryInstance.add(10),functionB(b: 20),functionC(c: 30),怎麼就有b,c,這是因為func add(a: Int) -> (b:Int) -> (c: Int) -> Int這個方法中a是第一個參數,預設是沒有外部參數名,只有餘下的參數才有外部參數名,b,c都屬於餘下的參數。/***** 系統的柯裡化函數調用 *****/var result: Int = curryInstance.addCur(10)(b: 20)(c: 30)/***** 系統的柯裡化函數拆解調用 *****/// 注意:Swift是強型別語言,這裡沒有報錯,說明調用系統柯裡化函數返回的類型和手動的functionB類型一致 // curryInstance.addCur(10) : 調用一個接收參數a,並且返回一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數// functionB: 一個接收參數b的函數,並且這個函數又返回一個接收參數c,傳回值為Int類型的函數functionB = curryInstance.addCur(10) // functionC: 一個接收參數c,傳回值為Int類型的函數functionC = functionB(b: 20) // result: 函數的傳回值res = functionC(c: 30) // 列印 60,60,60說明手動實現的柯裡化函數,和系統的一樣。println("\(r),\(res),\(result)")

 

柯裡化函數使用注意

 

1必須按照參數的定義順序來調用柯裡化函數,否則就會報錯。

var result: Int = curryInstance.addCur(10)(b: 20)(c: 30)

 

2、柯裡化函數的函數體只會執行一次,只會在調用完最後一個參數的時候執行柯裡化函數體。以下調用functionC(c: 30)才會執行函數體。這個可以自己斷點調試

// curried:柯裡化函數func addCur(a: Int)(b: Int)(c: Int) -> Int{    println("\(a) + \(b) + \(c)")    return a + b + c} // 建立柯裡化類的執行個體var curryInstance = Currying()// 不會執行柯裡化函數體functionB = curryInstance.addCur(10)// 不會執行柯裡化函數體functionC = functionB(b: 20)// 執行柯裡化函數體res = functionC(c: 30)

 

Swift中執行個體方法就是一個柯裡化函數

如何擷取執行個體方法?可以直接通過類擷取執行個體方法.

注意:方法是什麼類型,就返回什麼類型的函數,不過需要傳入一個參數(類執行個體)才能擷取到,如果方法中有外部參數名,外部參數名也屬於類型的一部分

使用類擷取執行個體方法:

 

 

Swift中執行個體方法的另一種調用方式(柯裡化調用)

// 建立柯裡化類的執行個體var curryInstance = Currying() // 調用function方法Currying.function(curryInstance)() // 拆解調用function方法// 1.擷取function方法let function = Currying.function(curryInstance)// 2.調用function方法function()

 

 

註解: 步驟都是一樣,首先擷取執行個體方法,在調用執行個體方法,執行個體方法怎麼調用,就不需要在教了。

柯裡化函數有什麼好處?為什麼要使用它?

這裡就需要瞭解函數式編程思想了,推薦看這篇文章函數式編程初探

特點:

1.只用“運算式”(運算式:單純的運算過程,總是有傳回值),不用“語句”(語句:執行某種操作,沒有傳回值)。2.不修改值,只返回新值。

好處:

1.代碼簡潔

2.提高代碼複用性

3.代碼管理方便,相互之間不依賴,每個函數都是一個獨立的模組,很容易進行單元測試。

4.易於“並發編程”,因為不修改變數的值,都是返回新值。

柯裡化函數就是運用了函數式編程思想,因此它也有以上的好處。

 

在iOS開發中如何運用柯裡化函數(實用性)

實用性一:複用性

需求1:地圖類產品,很多介面都有相同的功能模組,比如搜尋方塊。

我們可以利用柯裡化函數,來組裝介面,把介面分成一個個小模組,這樣其他介面有相同的模組,直接運用模組代碼,去重新組裝下就好了。

 

實用性二:延遲性,柯裡化函數代碼需要前面的方法調用完成之後,才會來到柯裡化函數代碼中。

需求2:閱讀類產品,一個介面的顯示,依賴於資料,需要載入完資料之後,才能判斷介面顯示。

這時候也可以利用柯裡化函數,來組裝介面,把各個模組載入資料的方法抽出來,等全部載入完成,在去執行柯裡化函數,柯裡化函數主要實現介面的組裝。

 

舉例說明:

// 組合介面// 為什麼要定義介面,為了程式的擴充性,以後只需要在介面中添加對應的組合方法就好了。protocol CombineUI{    func combine(top: () -> ())(bottom: () -> ())()} // 定義一個介面類,遵守組合介面class UI: CombineUI{    func combine(top: () -> ())(bottom: () -> ())() {        // 搭建頂部        top()        // 搭建底部        bottom()    }}

 

點擊下載:原始碼

來源:啊崢的簡書

微博:吖了個崢,歡迎交流。

 

|--> Copyright (c) 2015 Bing Ma.

|--> GitHub RUL: https://github.com/SpongeBob-GitHub

 

Swift # 柯裡化函數

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.