我从来没有从人为的 unmarshalling 和动词名词(AddTwo
类有一个 apply
增加两个!)示例中理解它。
我知道它是语法糖,所以(我从上下文推断)它一定是为了让一些代码更直观而设计的。
具有 apply
函数的类有什么意义?它的用途是什么,它使代码更好的目的是什么(解组,动词名词等)?
在伴生对象中使用它有什么帮助?
数学家有他们自己有趣的小方法,所以不像我们程序员说的那样说“然后我们调用函数 f
将它作为参数传递 x
”,他们谈论的是“将函数 f
应用到它的参数 x
”。
在数学和计算机科学中,Apply 是将函数应用于参数的函数。维基百科
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 中函数和对象之间差距的一种便捷方式。
它源于您经常想将某些东西应用于对象的想法。更准确的例子是工厂之一。当你有一个工厂时,你想给它应用参数来创建一个对象。
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 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)
不会编译,但由于伴随对象和应用,您可以调用 Seq(1, 2)
并且实现是由伴生对象选择。
这是一个小例子,供那些想要快速阅读的人使用
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")
}
输出 A greeter-1 正在用消息 hello 实例化 A greeter-2 正在用消息 world 实例化
来自 c++
的人员的 TLDR
它只是 ( )
括号的重载运算符
所以在斯卡拉:
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 - 将函数视为对象。
2 - apply 方法类似于 Python 中的 __call __,它允许您将给定类的实例用作函数。
粗略地说,
您可以将其视为自定义 ()operator
。如果类 X
具有 apply()
方法,则无论何时调用 X()
,您都将调用 apply()
方法。
apply 方法是将对象转换为函数的方法。希望能够使用函数语法,例如:
f(参数)
但是 Scala 同时具有函数式和面向对象的语法。一种或另一种需要成为语言的基础。 Scala(出于各种原因)选择面向对象作为语言的基本形式。这意味着任何函数语法都必须转换为面向对象的语法。
这就是 apply 的用武之地。任何具有 apply 方法的对象都可以使用以下语法:
f(参数)
然后,scala 基础架构将其转换为
f.apply(args)
f.apply(args) 具有正确的面向对象语法。如果对象没有 apply 方法,则无法进行此转换!
简而言之,在对象中拥有 apply 方法允许 Scala 将语法:object(args) 转换为语法:object.apply(args)。并且 object.apply(args) 是可以执行的形式。
仅供参考,这意味着 scala 中的所有函数都是对象。这也意味着拥有 apply 方法是使对象成为函数的原因!
请参阅已接受的答案,以更深入地了解函数如何成为对象,以及因此可以发挥的技巧。
class Average[YType](yZeroValue:YType)
。由于对象不能接受类型参数,你如何从它的对象中传递 YType?apply
和unapply
方法添加到类的伴随对象(除其他外)。因此,只用像case class Car(make:String, model: String, year: Short, color: String)
这样的一行定义一个类,就可以通过以下方式生成 Car 类的新对象:val myCar = Car("VW","Golf",1999,"Blue")
。这是Car.apply(...)
的简写every object can be treated as a function, provided it has the apply method
- 现在这么多是有道理的。