数学家有他们自己有趣的小方法,所以不像我们程序员所说的那样说“然后我们调用函数f 传递它x 作为参数”,他们谈论的是“将函数f 应用于它的参数x"。
在数学和计算机科学中,Apply 是一个应用函数
函数到参数。
Wikipedia
apply 的目的是缩小 Scala 中面向对象和函数式范式之间的差距。 Scala 中的每个函数都可以表示为一个对象。每个函数也有一个 OO 类型:例如,一个接受 Int 参数并返回 Int 的函数将具有 Function1[Int,Int] 的 OO 类型。
// define a function in scala
(x:Int) => x + 1
// assign an object representing the function to a variable
val f = (x:Int) => x + 1
由于在 Scala 中一切都是对象,f 现在可以被视为对 Function1[Int,Int] 对象的引用。例如,我们可以调用继承自Any 的toString 方法,这对于纯函数来说是不可能的,因为函数没有方法:
f.toString
或者我们可以通过在f 上调用compose 方法并将两个不同的函数链接在一起来定义另一个Function1[Int,Int] 对象:
val f2 = f.compose((x:Int) => x - 1)
现在,如果我们想实际执行函数,或者像数学家所说的“将函数应用于其参数”,我们将在 Function1[Int,Int] 对象上调用 apply 方法:
f2.apply(2)
每次你想执行一个表示为对象的函数时写f.apply(args)是面向对象的方式,但是会在不添加太多额外信息的情况下给代码添加很多混乱,如果能够使用更标准的符号,例如f(args)。这就是 Scala 编译器介入的地方,每当我们有对函数对象的引用 f 并写入 f (args) 以将参数应用于表示的函数时,编译器就会默默地将 f (args) 扩展为对象方法调用 f.apply (args)。
Scala 中的每个函数都可以被视为一个对象,并且它也可以以另一种方式工作 - 每个对象都可以被视为一个函数,前提是它具有 apply 方法。这样的对象可以用在函数符号中:
// we will be able to use this object as a function, as well as an object
object Foo {
var y = 5
def apply (x: Int) = x + y
}
Foo (1) // using Foo object in function notation
当我们希望将对象视为函数时,有很多用例。最常见的情况是factory pattern。我们可以将apply 对象添加到一组参数中来创建关联类的新实例,而不是使用工厂方法给代码添加混乱:
List(1,2,3) // same as List.apply(1,2,3) but less clutter, functional notation
// the way the factory method invocation would have looked
// in other languages with OO notation - needless clutter
List.instanceOf(1,2,3)
所以apply 方法只是缩小 Scala 中函数和对象之间差距的一种便捷方式。