浅谈 Swift 柯里化(Currying)

来源:互联网 发布:淘宝快递多久自动售货 编辑:程序博客网 时间:2024/05/21 13:16

       在 Swifter中,第一章 就是 讲解 柯里化。这本书 真的是非常的不错,值得一看,同时,正如作者王巍所说,国内的 大量的流水线书籍真的没必要买。如果 你希望入门,去这里,如果 你想提高,我非常推荐这本书。当然 你也可以在这里找到它的内容。

       继续说柯里化大笑

       先理解柯里化:把接受多个参数的方法变换成接受第一个参数的方法,并且 返回接受余下的参数并返回结果的新方法。用数学的思维很好理解,一个函数 xy ,当 传入 y = 2,返回的 就是 2x。

       写一个简单的例子。

     

    func JustForExample(a:Int)(b:Int) -> Int{         return a + b    }
        这个方法需要传入两个参数,但是我们没有写成 (a:Int,b:Int),而是分成了多个括号
       
    func  exampleUse() {        let exampleAdd = JustForExample(3) //只传入第一个参数,返回一个函数,函数为 Int ->Int        let result = exampleAdd(b:7)//传入 Int 返回 Int        print(result)    }    
       这就是柯里化的简单应用,当然 柯里化 在 js 等 中 也是很常用的。
       上面这段代码简单,但是下面这段代码 就不是很容易理解了。借鉴自:Ole Begemann

    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 会 在不久移除 柯里化 这种 申明语法,推荐使用简单的多参数设计。当然, 即使 要去掉,这种 有趣的知识, 也是值得学习的微笑



1 0