淺談 Swift 柯里化(Currying)
阿新 • • 發佈:2019-02-10
在 Swifter中,第一章 就是 講解 柯里化。這本書 真的是非常的不錯,值得一看,同時,正如作者王巍所說,國內的 大量的流水線書籍真的沒必要買。如果 你希望入門,去這裡,如果 你想提高,我非常推薦這本書。當然 你也可以在這裡找到它的內容。
繼續說柯里化:
先理解柯里化:把接受多個引數的方法變換成接受第一個引數的方法,並且 返回接受餘下的引數並返回結果的新方法。用數學的思維很好理解,一個函式 xy ,當 傳入 y = 2,返回的 就是 2x。
寫一個簡單的例子。
這個方法需要傳入兩個引數,但是我們沒有寫成 (a:Int,b:Int),而是分成了多個括號func JustForExample(a:Int)(b:Int) -> Int{ return a + b }
func exampleUse() {
let exampleAdd = JustForExample(3) //只傳入第一個引數,返回一個函式,函式為 Int ->Int
let result = exampleAdd(b:7)//傳入 Int 返回 Int
print(result)
}
這就是柯里化的簡單應用,當然 柯里化 在 js 等 中 也是很常用的。上面這段程式碼簡單,但是下面這段程式碼 就不是很容易理解了。借鑑自:
class BankAccount {
var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
}
定義了一個class,其中有一個方法 deposit(Double),
正常使用:
let account = BankAccount()
account.deposit(100) // balance = now
利用柯里化我們可以這麼寫:let depositor = BankAccount.deposit depositor(account)(100) // balance = 200
仔細觀察,我們發現depositor 沒有例項化一個BankAccout物件,而是直接引用他的deposit方法,這就類似於C語言的函式指標。然後通過 給depositor傳入一個例項化物件,返回一個 完整的deposit(Double)函式,然後 傳入一個Double,返回空。
拆開depositor我們 可以這麼寫:
let depositor: BankAccount -> (Double) -> ()
分成兩部分來看,第一部分: BankAccount -> (Double) 傳入一個 BankAccount例項,返回一個需要傳入Double的Function,
第二部分: (Double) -> () 傳入一個Double,返回 空,你應該理解為對 deposit() 的簽名。
然後是 原文照著這個思路 ,藉助柯里化 ,對target-acton的安全的改造。(因為 Swift的Selector 只能以字串生成,面臨難以重構的問題,並且無法再編譯期間檢查)。
以下是程式碼:
/// 目標事件協議
protocol TargetAction {
func performAction()
}
/**
OC中的委託
事件包裝結構,這裡是泛型,這裡表示傳入的資料型別可以是AnyObject
這個方法遵循TargetAction協議來處理事件
*/
struct TargetActionWrapper<T: AnyObject>:TargetAction{
weak var target: T?
//柯里化
let action: (T) -> () -> ()
func performAction() -> () {
if let t = target {
action(t)()
}
}
}
/// 列舉事件
enum ControlEvent {
case TouchUpInside
case ValueChanged
//...
}
/// 例子
class currying{
var actions = [ControlEvent :TargetAction]()
func setTarget<T:AnyObject>(target: T,action: (T) -> () -> (),controlEvent:ControlEvent){
actions[controlEvent] = TargetActionWrapper(target:target,action:action)
print(T)
print(action)
}
/// 移除
func removeTargetForControlEvent(controlEvent:ControlEvent){
actions[controlEvent] = nil
}
/// 執行
func performActionForControlEvent(controlEvent:ControlEvent){
actions[controlEvent]?.performAction()
}
}
使用:
class ViewController: UIViewController {
let button = currying()
override func viewDidLoad() {
super.viewDidLoad()
button.setTarget(self, action: ViewController.onButtonTap, controlEvent: .TouchUpInside)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func onButtonTap(){
}
func exampleUse() {
let exampleAdd = JustForExample(3) //只傳入第一個引數,返回一個函式,函式為 Int ->Int
let result = exampleAdd(b:7)//傳入 Int 返回 Int
print(result)
}
func JustForExample(a:Int)(b:Int) -> Int{
return a + b
}
}
寫在最後:
不知道為什麼,在你寫上面的example的時候,會告訴你,Swift 會 在不久移除 柯里化 這種 申明語法,推薦使用簡單的多引數設計。當然, 即使 要去掉,這種 有趣的知識, 也是值得學習的。