学习Swift系列之柯里化(Currying)

基本概念

柯里化背后的基本想法是函数可以局部应用,意思是一些参数值可以在函数调用之前被指定或者绑定。这个部分函数的调用会返回一个新的函数。

我们来举例说明:

比如,你需要写一个函数将输入的数字加1:

1
2
3
func addOne(num: Int) -> Int {
return num + 1
}

你可能很快就写出上面的函数了,但这个函数有一定的局限性,不够灵活。比如你还需要一个函数来实现加2或者加3的功能,岂不是又要重新再写两个函数。这时候你可能又会说简单,见下面代码:

1
2
3
4
5
6
7
8
func addTo(num: Int, withAdder adder: Int) -> Int {
return num + adder
}

let num = 10
let result1 = addTo(num: num, withAdder: 1) // 11
let result2 = addTo(num: num, withAdder: 2) // 12
let result3 = addTo(num: num, withAdder: 3) // 13

当然你这么做是完全没有问题的。那我们接下来看看怎么将上面的方法柯里化(Currying)

1
2
3
4
5
6
7
8
9
10
11
12
13
func addTo(_ adder: Int) -> (Int) -> Int {
return { num in
return num + adder
}
}

let num = 10
let addOne = addTo(1)
let addTwo = addTo(2)
let addThree = addTo(3)
let result1 = addOne(num) // 11
let result2 = addTwo(num) // 12
let result3 = addThree(num) // 13

从上面例子我们可以看到,adder这个参数在函数调用前就被指定,然后返回一个新的函数,然后我们就可以调用新的函数来实现功能了。

类实例方法与柯里化

实例方法是柯里化 (currying) 函数

类实例方法

首先我们创建一个简单的BankAccount类

1
2
3
4
5
6
7
class BankAccount {
var balance: Double = 0.0

func deposit(amount: Double) {
balance += amount
}
}

我们正常使用这个类会是这样

1
2
let account = BankAccount()
account.deposit(amount: 100) // balance == 100

我们也可以这样使用

1
2
3
4
let account = BankAccount()
let depositor = BankAccount.deposit // depositor的类型:(BankAccount) -> (Double) -> ()
let depositorFunc = depositor(account) // depositorFunc的类型:(Double) -> ()
depositorFunc(100) // balance == 100

从上面我们可以看出实例方法也是柯里化 (currying) 函数

结构体实例方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct BankAccount {
var balance: Double = 0.0

mutating func deposit(amount: Double) {
balance += amount
}
}

var account = BankAccount()
account.deposit(amount: 100) // balance == 100

let depositor = BankAccount.deposit // (inout BankAccount) -> (Double) -> ()
let depositorFunc = depositor(&account) // (Double) -> ()
depositorFunc(100) // balance == 200

因为结构体类是值类型,类是引用类型,所以他们的实现有细微不同。但本质上是一样的,可以看出实例方法都是柯里化 (currying) 函数

参考