剥掉Scala的糖衣(7) -- apply method
apply method是一个很简单的语言特性。如果一个class或者是object有一个主要的方法,那么与其每次显式的调用这个主要的方法,还不如隐式调用。举个例子:
1 | class Kettle { |
一个水壶的主要作用就是烧开水,于是我们每次都要调用boil方法来烧开水:
1 | val kettle: Kettle = new Kettle() |
如果要把它改写成apply method的方式,只需要给boil改个名字就好了:
1 | class Kettle { |
然后需要烧开水时,就只需把水倒进壶里就好了:
1 | val kettle: Kettle = new Kettle() |
这个语言特性的实现很简单,不用说也可以猜到,无非就是把kettle(water)编译成kettle.apply(water)。反编译一下,Kettle class的定义毫无出奇之处:
1 | public class Kettle |
烧水的代码被编译成了这样:
1 | Kettle kettle = new Kettle(); |
我们刚开始说过apply method也可以用在object里。下面举个例子,我们把Kettle烧水的能力移到它的companion object里面去:
1 | object Kettle { |
然后烧水的时候就可以这样调用:
1 | Kettle(new Water()) |
反编译出来的结果大同小异,就不再赘述了,唯一的区别就是apply变成了静态方法。
上面这个水壶烧水的例子并不是最佳实践的作法。apply method的一个最佳实践是用来做工厂。比如Scala标准库中的List就提供了apply方法来给我们创建List:
1 | List(1, 2, 3) |
或者是Map也有类似的用法:
1 | Map(1 -> "a", 2 -> "b", 3 -> "c") |
以上的两段代码并不是在调用List和Map的constructor,而是在调用List和Map的companion objects的apply方法。
Map的创建可以用apply method,而Map最常用的一个方法就是通过key来取得value,这个也有apply method来做:
1 | val map = Map(1 -> "a", 2 -> "b", 3 -> "c") |