关于scala中的特殊方法apply,先给一个比较通俗的解释。
当对象(伴生对象)以函数的方式进行调用时,scala 会隐式地将调用改为在该对象上调用apply方法。
例如: Demo(“hello”) 实际调用的是 Demo.apply(“hello”), 因此apply方法又被称为注入方法。
apply方法常用于创建类实例的工厂方法。
case class SomeBean(name: String, age: Int)
对于这个 case 类会生成一个 SomeBean 的伴生对象 SomeBean,这个伴生对象中定义了 apply 与 unapply 方法。
下面这段代码是反编译后得到的
public Option<Tuple2<String, Object>> unapply(SomeBean x$0) {
return x$0 == null ? None..MODULE$ : new Some(new Tuple2(x$0.name(), BoxesRunTime.boxToInteger(x$0.age())));
}
public SomeBean apply(String name, int age) {
return new SomeBean(name, age);
}
apply
将对象以函数的方式进行调用时,scala会隐式地将调用改为在该对象上调用apply方法。例如XXX(“hello”)实际调用的是XXX.apply(“hello”), 因此apply方法又被称为注入方法。apply方法常用于创建类实例的工厂方法。
定义在 object 中
object Greeting{
def apply(name: String) = "Hello " + name
}
Greeting.apply(“Lucy”) //与下面的调用等价
Greeting(“Lucy”) //结果为 Hello Lucy
定义在 class 或 trait 中
首先我们来看下 scala 集合类 List 对 apply 的使用。scala 中 List 在读取数据时与 java 的 List 不同。
java 中使用 list.get(index) 取得第 index 个索引的数据,但在 scala 中只需要使用 list(index )就可以实现。
这个功能就是借助于 apply 方法实现的。例如:
List(1, 2, 3)
List("a", "b", "c")
或者是Map也有类似的用法:
Map(1 -> "a", 2 -> "b", 3 -> "c")
以上的两段代码并不是在调用 List 和 Map 的 constructor,而是在调用 List 和 Map 的伴生对象(companion objects)的 apply 方法。
下面我们来实际使用 apply 方法来显示获取特定位置的字符的需求(类似与模拟 Map 和 List 中的取值方法)
class IndexedString(val str: String) {
def apply(charIndex: Int) = str.charAt(charIndex)
}
我们可以通过 IndexedString 的 apply 方法可以通过索引读取在字符中对应的字符
val indexed = new IndexedString("Hello world")
indexed(0) //结果为H, 等价于indexed.apply(0)
scala 的函数对象
scala 中的函数对象(头等函数或first-class function)是使用 apply 的典型用法:scala 中的函数对象是scala.FunctionN 特质的实例,使用时函数对象直接调用 FunctionN 的 apply 方法。
scala> val increment: (Int) => Int = _ + 1
increment: Int => Int = <function1>
// 调用 scala.FunctionN的apply方法
scala> increment(0)
res0: Int = 1
unapply
与 apply 相对的是 unapply 方法,它的用法与 apply 类似,但其作用是用来抽取部分参数,它也称为抽取方法,主要用于模式匹配时抽取某些参数 case XXX(str) => println(str)