Scala中的apply函数是什么?

我从来没有从做作的解组和动词名词(一个AddTwo类有一个apply,它增加了两个!)的例子中理解它。

我知道它是语法糖,所以(我从上下文推断)它一定是为了使一些代码更直观而设计的。

具有apply函数的类具有什么意义?它的用途是什么,它使代码更好的目的是什么(解组、动词名词等)?

它在伴生对象中使用时有什么帮助?

148915 次浏览

它来自于你经常想要应用某物到一个对象的想法。更准确的例子是工厂。当你有一个工厂时,你想给它应用形参来创建一个对象。

Scala的人认为,在许多情况下,有一个调用apply的快捷方式会很好。因此,当你直接给一个对象参数时,它就像你把这些参数传递给该对象的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提供一个很好的工厂方法,下面是一个例子:

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是一个trait,因此new Seq(1, 2)不会被编译,但由于伴生对象和apply,你可以调用Seq(1, 2),实现由伴生对象选择。

数学家有他们自己有趣的方法,所以他们不是说“然后我们调用函数f,将x作为参数传递给它”,就像我们程序员说的那样,他们说“将函数f应用到它的参数x”。

在数学和计算机科学中,Apply是应用的函数 函数的参数 维基百科 < / em >

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]对象的引用。例如,我们可以调用继承自AnytoString方法,这对于纯函数来说是不可能的,因为函数没有方法:

  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

在很多情况下,我们都希望将对象视为函数。最常见的场景是工厂模式。我们可以将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中缩小函数和对象之间差距的一种方便方法。

这里有一个小例子,供那些想要快速阅读的人使用

 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")




}

输出

使用消息hello实例化了一个greeting -1

使用消息世界实例化了一个greeting -2

来自c++的人的TLDR

它只是( )括号的重载操作符

在scala中:

class X {
def apply(param1: Int, param2: Int, param3: Int) : Int = {
// Do something
}
}

在c++中与此相同:

class X {
int operator()(int param1, int param2, int param3) {
// do something
}
};

1 -将函数视为对象。

apply方法类似于Python中的< >强__call __ < / >强,它允许你使用给定类的实例作为函数。

简单地说,

你可以把它看作是自定义的()operator。如果类X具有apply()方法,那么无论何时调用X(),都将调用apply()方法。

apply方法将对象转换为函数。我们希望能够使用函数语法,例如:

f (args)

但是Scala同时拥有函数语法和面向对象语法。其中一个必须是语言的基础。Scala(出于各种原因)选择面向对象作为语言的基本形式。这意味着任何函数语法都必须转换为面向对象的语法。

这就是应用的用武之地。任何具有apply方法的对象都可以使用以下语法:

f (args)

然后scala基础架构将其转换为

f.apply (args)

F.apply (args)具有正确的面向对象语法。如果对象没有apply方法,则不可能执行此转换!

简而言之,在对象中使用apply方法可以让Scala将语法:object(args)转换为语法:object.apply(args)。而object.apply(args)则处于可以执行的表单中。

供你参考,这意味着scala中的所有函数都是对象。它还暗示了apply方法是使对象成为函数的原因!

查看公认的答案,了解函数是如何成为对象的,以及可以作为对象使用的技巧。