curry 是 Swift 中一个很灵活的特性,用最简单的语言来说,curry 就是一个用方法生成方法的机制。它能让我们的方法定义更加动态化,甚至对于系统内置的方法,都可以通过 curry 的方法进行整合。
我们之前的一篇文章,介绍了 curry 的基本用法,这次我们继续上次的探讨,来继续延伸一下 curry 机制的使用范围。
关于 curry 的基本用法,可以参看我们之前的文章:
curry 作用于系统内置方法
我们前面的文章中,介绍了如何对我们自己定义的方法进行 curry 处理,那么如果系统内置的方法,或者别的第三方库中定义的方法呢。我们又如何使用对他们应用 curry 呢?
我们可以创造一个示例,我们为 NSNumber 定义一个方法 multiple:
extension NSNumber {
class func multiple(left: Int, right:Int) -> Int {
return left * right
}
}
在我们不改变这个方法的定义的情况下,怎样能它支持 curry 特性呢。
我们可以定义一个函数,叫做 curry:
func curry(function: (Int,Int) -> Int) -> (Int -> (Int -> Int)){
}
这一大串的定义看着有点眼花缭乱,那么咱们一一解释吧, 首先 curry 接受的参数类型为 (Int,Int) -> Int。 这个表示的是接受两个 Int 类型的参数,并返回一个 Int 类型。也就是我们在 NSNumber 扩展中定义的 multiple 函数类型。 我们可以将 Number.multiple 作为参数传给这个方法。
再看它的返回值,(Int -> (Int -> Int)) 这个表示的是接受 1 个 Int 类型参数,并返回一个 Int -> Int 类型的返回值。这个返回值嘛,毫无疑问又是一个函数。这个返回的函数是一个接受 1 个 Int 参数并返回一个 Int 类型返回值的函数。
curry 这个函数,会把传给它的函数转换成另一个带有 currying 特性的函数。
我们来看看它是如何实现的吧:
func curry(function: (Int,Int) -> Int) -> (Int -> (Int -> Int)){
return { a in
{ b in
return function(a,b)
}
}
}
return 语句首先返回一个外层的闭包:
这个闭包对应的返回值类型 (Int -> (Int -> Int)),然后第一步闭包内又包含了另外一个闭包:
{ a in
//...
}
因为我们 curry 函数的返回值类型是 (Int -> (Int -> Int)), 它还会返回另外一个函数,所以才需要下一层闭包,它对应的是 (Int -> (Int -> Int)) 中的后半部分 (Int -> Int) 类型。
{ b in
return function(a,b)
}
然后最内层的闭包中,调用了 function 函数,将参数 a b 传入进去完成了函数的计算。 function 函数其实对应的就是我们定义的 NSNumber.multiple 方法。
我们来看一下调用方法:
let curriedMultiple = curry(NSNumber.multiple)
curriedMultiple(3)(2)
curry 函数将 NSNumber.multiple 方法转换成了 curriedMultiple 函数,这个函数是支持 curry 特性的函数,所以我们就可以用 curriedMultiple(3)(2) 这种形式调用它了。
这个特性比较灵活。
更通用的做法
我们自己定义的 curry 函数可以将 NSNumber 的 multiple 这个方法转换成支持 currying 特性的函数,但这个 curry 函数受限于参数类型,只能对 Int 类型参数的方法进行转换。
我们还可以使用 Swift 的泛型机制,让这个方法的适应性更强:
func curry(function: (A,B) -> C) -> (A -> (B -> C)){
return { a in
{ b in
return function(a,b)
}
}
}
通过泛型,我们将具体的参数类型变成了类型参数 A,B,C 这种形式。这样我们的这个 curry 方法就可以对任何接受两个参数的方法进行 currying 处理了。
比如定义了这两个方法:
extension NSNumber {
class func multiple(left: Int, right:Int) -> Int {
return left * right
}
class func add(left:Double, right:Double) -> Double {
return left + right
}
}
就可以使用 curry 函数对这样个方法进行操作:
curry(NSNumber.multiple)(3)(3) // 9
curry(NSNumber.add)(3.0)(3.0) // 6.0
通过泛型,让 curry 函数的使用更加通用。
那么还有一个问题,就是参数的个数,如果我们的参数个数是三个或者更多呢。
已经有人为我们解决这个问题了,就是 Curry 第三方库,它的 Guthub 主页:
这个库的实现原理就是我们这篇文章所讲的内容,并且它支持了任意参数数量。
本站文章均为原创内容,如需转载请注明出处,谢谢。