Scala中的应用函数是什么?
我从来没有从人为的反编组和名词中理解它(一个AddTwo
类有一个apply
,增加了两个!)的例子。
我知道它是句法糖,所以(我从上下文中推导出来的)一定是为了让一些代码更直观而devise的。
带有apply
函数的类有什么意义? 它的用途是什么,它是什么目的使代码更好(解组,名词等)?
在伴侣对象中使用它有什么帮助?
math家有自己的一些有趣的方法,所以我们不是说程序员会说“那么我们把函数f
作为一个parameter passing给它”,而是说“把函数f
应用到它的参数x
”。
在math和计算机科学中,Apply是一个将函数应用于参数的函数。
维基百科
apply
于缩小Scala中面向对象和function范例之间差距的目的。 Scala中的每个函数都可以表示为一个对象。 每个函数还有一个OOtypes:例如,一个接受一个Int
参数并返回一个Int
的Function1[Int,Int]
将具有OOtypes的Function1[Int,Int]
。
// 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中的一个对象,因此现在可以将其视为对Function1[Int,Int]
对象的引用。 例如,我们可以调用从Any
inheritance的toString
方法,这对纯函数来说是不可能的,因为函数没有方法:
f.toString
或者我们可以通过调用f
上的compose
方法并将两个不同的函数链接在一起来定义另一个Function1[Int,Int]
对象:
val f2 = f.compose((x:Int) => x - 1)
现在,如果我们想要实际执行函数,或者像math家所说的“将函数应用于其参数”那么我们将在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
当我们想把一个对象作为一个函数的时候,有很多的用例。 最常见的情况是工厂模式 。 我们可以apply
对象应用于一组参数来创build关联类的新实例,而不是使用工厂方法将代码添加到代码中:
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中函数和对象之间差距的一个方便的方法。
它来自于你经常想要将东西应用于某个对象的想法。 更准确的例子是工厂之一。 当你有一个工厂时,你想要应用参数来创build一个对象。
斯卡拉人认为,如果发生在很多情况下,可以有一个快捷方式来调用apply
。 因此,当你给参数直接给一个对象的时候,就像把这些parameter passing给这个对象的apply函数一样:
class MyAdder(x: Int) { def apply(y: Int) = x + y } val adder = new MyAdder(2) val result = adder(4) // equivalent to x.apply(4)
它常常用于伴侣对象,为类或特质提供一个漂亮的工厂方法,下面是一个例子:
trait A { val x: Int def myComplexStrategy: Int } object A { def apply(x: Int): A = new MyA(x) private class MyA(val x: Int) extends A { val myComplexStrategy = 42 } }
从scala标准库,你可能会看scala.collection.Seq
是如何实现的: Seq
是一个特征,因此new Seq(1, 2)
不会编译,但是由于伴侣对象和apply,你可以调用Seq(1, 2)
,实现是由伴侣对象select的。
对于那些想快速阅读的人来说,这是一个小例子
object ApplyExample01 extends App { class Greeter1(var message: String) { println("A greeter-1 is being instantiated with message " + message) } class Greeter2 { def apply(message: String) = { println("A greeter-2 is being instantiated with message " + message) } } val g1: Greeter1 = new Greeter1("hello") val g2: Greeter2 = new Greeter2() g2("world") }
产量
greeter-1正在用消息hello实例化
迎宾2正在与消息世界实例化