柯里化(Currying),又稱部分求值(Partial Evaluation),是一種函數式編程思想,就是把接受多個參數的函數轉換成接收一個單一參數(最初函數的第一個參數)的函數,而且返回一個接受餘下參數的新函數技術。html
uncurried: 普通函數編程
// 接收多個參數的函數(與類相關的函數,統稱爲方法,可是這裏就直接說函數了,方便理解) func add(a: Int, b: Int, c: Int) -> Int { print("\(a) + \(b) + \(c)") return a + b + c }
curried: 柯里化函數swift
// 柯里化函數,Swift 3.0 以前支持這樣的語法,能夠直接寫 func addCur(a: Int)(b: Int)(c: Int) -> Int { println("\(a) + \(b) + \(c)") return a + b + c }
定義柯里化函數閉包
func function name (parameters)(parameters) -> return type { statements }
uncurried: 普通函數併發
class Currying { // 接收多個參數的函數 func add(a: Int, b: Int, c: Int) -> Int { print("\(a) + \(b) + \(c)") return a + b + c } }
系統自帶的柯里化函數函數式編程
class Currying { func addCur(a: Int)(b: Int)(c: Int) -> Int { print("\(a) + \(b) + \(c)") return a + b + c } }
手動實現柯里化函數函數
把上面的函數轉換爲柯里化函數,首先轉成接收第一個參數 a
,而且返回接收餘下第一個參數 b
的新函數(採用閉包).單元測試
這裏爲何能使用參數 a、b、c
?測試
a、b、c
都在閉包中。class Currying { // (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; } } } }
建立柯里化類的實例lua
var curryInstance = Currying()
手動實現的柯里化函數調用
var result: Int = curryInstance.add(a: 10)(b: 20)(c: 30)
[[Person alloc] init]
,這種寫法應該都見過吧,就是一下發送了兩個消息,alloc
返回一個實例,再用實例調用 init
初始化,上面也是同樣,一下調用多個函數,每次調用都會返回一個函數,而後再次調用這個返回的函數。手動實現的柯里化函數拆解調用
curryInstance.add(a: 10)
調用一個接收參數 a
,而且返回一個接收參數 b
的函數,而且這個函數又返回一個接收參數 c
,返回值爲 Int
類型的函數。
// functionB: 一個接收參數 b 的函數,而且這個函數又返回一個接收參數 c,返回值爲 Int 類型的函數 let functionB = curryInstance.add(a: 10)
functionB(b: 20)
調用一個接收參數 b
的函數,而且這個函數又返回一個接收參數 c
,返回值爲 Int
類型的函數。
// functionC: 一個接收參數 c,返回值爲 Int 類型的函數 let functionC = functionB(b: 20)
functionC(c: 30)
調用一個接收參數 c
,返回值爲 Int
類型的函數。
// result: 函數的返回值 var result: Int = functionC(c: 30);
系統的柯里化函數調用
var result: Int = curryInstance.addCur(a: 10)(b: 20)(c: 30)
系統的柯里化函數拆解調用
curryInstance.addCur(a: 10)
調用一個接收參數 a
,而且返回一個接收參數 b
的函數,而且這個函數又返回一個接收參數 c
,返回值爲 Int
類型的函數。
// Swift是強類型語言,這裏沒有報錯,說明調用系統柯里化函數返回的類型和手動的 functionB 類型一致 // functionB: 一個接收參數 b 的函數,而且這個函數又返回一個接收參數 c,返回值爲 Int 類型的函數 functionB = curryInstance.addCur(a: 10)
functionB(b: 20)
調用一個接收參數 b
的函數,而且這個函數又返回一個接收參數 c
,返回值爲 Int
類型的函數。
// functionC: 一個接收參數c,返回值爲Int類型的函數 functionC = functionB(b: 20)
functionC(c: 30)
調用一個接收參數 c
,返回值爲 Int
類型的函數。
// result: 函數的返回值 result = functionC(c: 30) // 打印 60,60,60 說明手動實現的柯里化函數,和系統的同樣。 print("\(r), \(res), \(result)")
必須按照參數的定義順序來調用柯里化函數,不然就會報錯。
柯里化函數的函數體只會執行一次,只會在調用完最後一個參數的時候執行柯里化函數體。
如下調用 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(a: 10) // 不會執行柯里化函數體 functionC = functionB(b: 20) // 執行柯里化函數體 result = functionC(c: 30)
這裏就須要瞭解函數式編程思想了,柯里化函數就是運用了函數式編程思想,推薦看這篇文章函數式編程初探。
特色
好處
實用性一:複用性
需求 1:地圖類產品,不少界面都有相同的功能模塊,好比搜索框。
實用性二:延遲性
柯里化函數代碼須要前面的方法調用完成以後,纔會來到柯里化函數代碼中。
需求 2:閱讀類產品,一個界面的顯示,依賴於數據,須要加載完數據以後,才能判斷界面顯示。
舉例說明
// 組合接口 // 爲何要定義接口,爲了程序的擴展性,之後只須要在接口中添加對應的組合方法就行了。 protocol CombineUI { func combine(top: () -> ())(bottom: () -> ())() } // 定義一個界面類,遵照組合接口 class UI: CombineUI { func combine(top: () -> ())(bottom: () -> ())() { // 搭建頂部 top() // 搭建底部 bottom() } }
Swift 中實例方法的柯里化調用
示例結構體
struct Example { var internalStr = "" func combine(externalStr: String) { print(internalStr + " " + externalStr) } }
調用實例方法的經常使用格式
let example = Example(internalStr: "hello") example.combine(externalStr: "word") // hello word
調用實例方法的柯里化格式
let example = Example(internalStr: "hello") Example.combine(example)(externalStr: "word") // hello word