我从来没有从人工编组和动词名词(一个AddTwo类有一个添加两个的应用程序!)示例中理解它。

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

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

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


当前回答

它来自于你经常想要将某些东西应用到一个对象上的想法。更准确的例子是工厂。当您有一个工厂时,您希望向其应用参数以创建一个对象。

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

其他回答

它来自于你经常想要将某些东西应用到一个对象上的想法。更准确的例子是工厂。当您有一个工厂时,您希望向其应用参数以创建一个对象。

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

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

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

apply的目的是缩小Scala中面向对象和函数式范式之间的差距。Scala中的每个函数都可以表示为对象。每个函数也都有一个面向对象类型:例如,一个接受Int形参并返回Int的函数的面向对象类型为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中所有东西都是对象,f现在可以被视为对Function1[Int,Int]对象的引用。例如,我们可以调用从Any继承的toString方法,这对于纯函数来说是不可能的,因为函数没有方法:

  f.toString

或者我们可以定义另一个Function1[Int,Int]对象,通过调用f上的compose方法并将两个不同的函数链接在一起:

 val f2 = f.compose((x:Int) => x - 1)

现在,如果我们想真正执行这个函数,或者像数学家说的“将一个函数应用到它的参数”,我们将调用Function1[Int,Int]对象上的apply方法:

 f2.apply(2)

Writing f.apply(args) every time you want to execute a function represented as an object is the Object-Oriented way, but would add a lot of clutter to the code without adding much additional information and it would be nice to be able to use more standard notation, such as f(args). That's where Scala compiler steps in and whenever we have a reference f to a function object and write f (args) to apply arguments to the represented function the compiler silently expands f (args) to the object method call 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 

在很多情况下,我们都希望将对象视为函数。最常见的场景是工厂模式。我们可以将object应用于一组参数来创建关联类的新实例,而不是使用工厂方法在代码中添加混乱:

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 method只是在Scala中缩小函数和对象之间差距的一种方便方法。

1 -将函数视为对象。

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

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

 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

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方法是使对象成为函数的原因!

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