我从来没有从设计的解组和修饰名词中理解它(AddTwo
类有一个apply
加上两个!)的例子。
我理解它是语法糖,所以(我从上下文推断)它必须设计成使一些代码更直观。
具有apply
功能的班级有什么意义?它用于什么,以及它使代码变得更好的目的(解组,修改名词等)?
在伴侣对象中使用它有何帮助?
答案 0 :(得分:581)
数学家有他们自己的一些有趣的方式,所以不要说“然后我们称函数f
将x
作为参数传递”,正如我们程序员所说,他们谈论“应用函数{{ 1}}到它的参数f
“。
在数学和计算机科学中,Apply是一个适用的函数 参数的功能。
Wikipedia
x
旨在缩小Scala中面向对象和功能范例之间的差距。 Scala中的每个函数都可以表示为一个对象。每个函数也有一个OO类型:例如,一个带有apply
参数并返回Int
的函数的OO类型为Int
。
Function1[Int,Int]
由于Scala // define a function in scala
(x:Int) => x + 1
// assign an object representing the function to a variable
val f = (x:Int) => x + 1
中的所有内容都是对象,因此现在可以将其视为对f
对象的引用。例如,我们可以调用从Function1[Int,Int]
继承的toString
方法,这对于纯函数来说是不可能的,因为函数没有方法:
Any
或者我们可以通过调用 f.toString
上的Function1[Int,Int]
方法并将两个不同的函数链接在一起来定义另一个compose
对象:
f
现在,如果我们想要实际执行该函数,或者数学家说“将函数应用于其参数”,我们将在 val f2 = f.compose((x:Int) => x - 1)
对象上调用apply
方法:
Function1[Int,Int]
每次要执行表示为对象的函数时,编写 f2.apply(2)
都是面向对象的方式,但是会在不添加太多额外信息的情况下为代码添加大量混乱,这样会很好能够使用更标准的表示法,例如f.apply(args)
。这就是Scala编译器的步骤,每当我们对函数对象有一个引用f(args)
并编写f
以将参数应用于所表示的函数时,编译器会静默地将f (args)
扩展为对象方法调用{ {1}}。
Scala中的每个函数都可以被视为一个对象,它也可以用于其他方式 - 只要它具有f (args)
方法,每个对象都可以被视为一个函数。这些对象可以在函数表示法中使用:
f.apply (args)
当我们想要将对象视为函数时,有许多用例。最常见的情况是factory pattern。我们可以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
方法只是缩小Scala中函数和对象之间差距的一种方便方法。
答案 1 :(得分:44)
它来自于您经常想要将某些东西应用于对象的想法。更准确的例子是工厂之一。当您有工厂时,您希望将参数应用于它以创建对象。
斯卡拉家伙认为,在许多情况下都会发生这种情况,有一个快捷方式可以调用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)
,并由配对对象选择实现。
答案 2 :(得分:7)
对于那些想要快速阅读的人来说,这是一个小例子
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
实例化greeter-1greeter-2正在使用消息世界进行实例化
答案 3 :(得分:0)
来自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
}
};
答案 4 :(得分:0)
1 - 将函数视为对象。
2 - apply 方法类似于 Python 中的 __call __,它允许您将给定类的实例用作函数。