ChatGPT解决这个技术问题 Extra ChatGPT

Scala 中的 apply 函数是什么?

我从来没有从人为的 unmarshalling 和动词名词(AddTwo 类有一个 apply 增加两个!)示例中理解它。

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

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

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

即使是快速的谷歌搜索也会带来很多不错的文章。这是一个:jackcoughonsoftware.blogspot.com/2009/01/…
实际上它与 Java/C++ 中的构造函数相同,但可以返回值并具有“应用”名称
这是一个方法,而不是一个函数。方法和函数之间的区别在 Scala 中非常重要。
详细说明 Zoidberg,“方法只是可以访问类状态的函数”twitter.github.io/scala_school/basics.html 通常这不仅仅适用于 Scala stackoverflow.com/questions/155609/…

M
Muhammad Hewedy

数学家有他们自己有趣的小方法,所以不像我们程序员说的那样说“然后我们调用函数 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 中函数和对象之间差距的一种便捷方式。


您将如何将自定义变量类型添加到对象。 AFAIK 这是不可能的。这是一个示例:您有这个类 class Average[YType](yZeroValue:YType)。由于对象不能接受类型参数,你如何从它的对象中传递 YType?
Scala 中的类型通常可以根据参数推断,但如果不是,您可以通过方括号提供它们。所以当实例化一个 Average 对象时,你可以说“val avg = new Average[Int](0)”
案例类在这里值得一提。案例类方便、自动且不可见地将 applyunapply 方法添加到类的伴随对象(除其他外)。因此,只用像 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 - 现在这么多是有道理的。
T
Tristan Reid

它源于您经常想将某些东西应用于对象的想法。更准确的例子是工厂之一。当你有一个工厂时,你想给它应用参数来创建一个对象。

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) 并且实现是由伴生对象选择。


是否也可以使用 Implicits 来完成 apply 的等效操作?
s
sdinesh94

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

 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 实例化


g2 的消息是否正确?这实际上是在实例化时发生的,还是实际上是在实例化之后发生的(即使它是延迟实例化的)?
T
Tomáš Růžička

来自 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
   }
};

j
jiawei hu

1 - 将函数视为对象。

2 - apply 方法类似于 Python 中的 __call __,它允许您将给定类的实例用作函数。


Ö
Özgür

粗略地说,

您可以将其视为自定义 ()operator。如果类 X 具有 apply() 方法,则无论何时调用 X(),您都将调用 apply() 方法。


s
seanhalle

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

请参阅已接受的答案,以更深入地了解函数如何成为对象,以及因此可以发挥的技巧。