1、什么是柯里化?
柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数切返回结果的新函数的技术
用数学理解就是:一个函数求xy,当传入y=2时,返回的就是2x
2、简单示例
例如:实现一个函数,输入的是任一整数,输出要返回输入的整数+2
一般的写法是
func addTwo(_ a : Int)->Int{ return a+2 }
上面这种写法就只是简单的可以实现这个函数,并没有进行优化,且不通用,里面的+2直接固定写死了,如果要实现+4/+6/+8,不能每次都去重新定义一个函数,我们需要定义一个通用的函数,所以需要做如下改进,主要利用的是swift的currying技术
func addTwo(_ a : Int)->(Int)->Int{ return {b in return a+b } }
上面的函数可以简化成
func addTwo(_ a : Int)->(Int)->Int{ return {b in a+b } }
还可以更通用一些,将参数定义为泛型
//两个参数的泛型 func curry<A, B>(_ function:@escaping (A)->B)->(A)->B{ return {a in function(a)} } //三个参数的泛型 func curry<A, B, C>(_ function:@escaping (A, B)->C)->(A)->(B)->C{ return {a in {b in function(a,b)}} } //四个参数的泛型 func curry<A, B, C, D>(_ function:@escaping (A, B, C)->D)->(A)->(B)->(C)->D{ return {a in {b in {c in function(a, b, c)}}} } //currying调用 func addTwo(_ a : Int, _ b : Int)->Int{ return a+b } let result = curry(addTwo)(1)(2) //打印的结果为3
3、项目中的实际应用
主要应用在需要传多个参数的函数,
1)例如:假设有这样一个需求,我需要记录某个系统的日志,日志需要包含以下几个要素:操作人的名字name,时间time,日志类型type和日志内容msg。
func curry<A, B, C, D, E>(_ function:@escaping (A, B, C, D)->E)->(A)->(B)->(C)->(D)->E{ return {a in {b in {c in {d in function(a, b, c, d)}}}} } func createLogInfo(_ name : String, _ time : String, _ type : String, _ msg : String)->String{ return "name : \(name)\n" + "type : \(type)\n" + ("message : \(msg)\n" + "time: \(time) ") } //调用 let createLogInfoResult = curry(createLogInfo)("functionName")("today")("Error")("somethingWrong") 输出结果: name : functionName type : Error message : somethingWrong time: today
2)封装target-action,对其安全的改造
原因:由于swift的selector智能是字符串生成,面临难以重构的问题,并且无法在编译期间检查
改造的步骤:
(1)定义一个目标事件协议
//目标事件协议 protocol TargetAction { func performAction() }
(2)定义一个类,遵循(1)中的协议来处理事件
/** OC中的委托 事件包装结构,这里是泛型,这里表示传入的数据类型可以是AnyObject 这个方法遵循TargetAction协议来处理事件 */ struct TargetActionWrapper<T: AnyObject>:TargetAction { weak var target : T? //柯里化 let action : (T) -> () -> () func performAction() { if let t = target { action(t)() } } }
(3)枚举事件的类型
//枚举 enum ControlEvent{ case TouchUpInside case ValueChanged //... }
(4)示例
//示例 class currying{ var actions = [ControlEvent : TargetAction]() func setTarget<T: AnyObject>(_ target : T, _ action : @escaping (T)->()->(), _ controlEvent : ControlEvent){ actions[controlEvent] = TargetActionWrapper(target: target, action: action) print("T \(T.self)") print("action \(action)") } //移除 func removeTargetForControlEvent(_ controlEvent : ControlEvent){ actions[controlEvent] = nil } //执行 func performActionForControlEvent(_ controlEvent : ControlEvent){ actions[controlEvent]?.performAction() } }
(5)在项目中的实际使用
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() currying().setTarget(self, ViewController.btnclick, .TouchUpInside) } func btnclick(){ print("点击了") } }