Scala中的apply函数是什么?

Jes*_*ose 297 scala

我从来没有从设计的解组和修饰名词中理解它(一个AddTwoapply增加了两个!)的例子.

我理解它是语法糖,所以(我从上下文推断)它必须被设计为使一些代码更直观.

具有apply函数的类有什么意义?它用于什么,以及它使代码变得更好的目的(解组,修改名词等)?

在伴侣对象中使用时如何帮助?

Vla*_*dim 616

数学家有他们自己的一些有趣的方式,所以不是说"然后我们称函数f将它x作为参数传递",正如我们程序员所说,他们谈论"将函数f应用于它的论证x".

在数学和计算机科学中,Apply是一个将函数应用于参数的函数.
维基百科

apply用于缩小Scala中面向对象和功能范例之间的差距.Scala中的每个函数都可以表示为一个对象.每个函数也有一个OO类型:例如,一个接受Int参数并返回一个Int将具有OO类型的函数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
Run Code Online (Sandbox Code Playgroud)

由于Scala中的所有内容都是对象,f因此现在可以将其视为Function1[Int,Int]对象的引用.例如,我们可以调用toString继承自的方法Any,这对于纯函数来说是不可能的,因为函数没有方法:

  f.toString
Run Code Online (Sandbox Code Playgroud)

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

 val f2 = f.compose((x:Int) => x - 1)
Run Code Online (Sandbox Code Playgroud)

现在,如果我们想要实际执行函数,或者数学家说"将函数应用于其参数",我们将applyFunction1[Int,Int]对象上调用该方法:

 f2.apply(2)
Run Code Online (Sandbox Code Playgroud)

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 
Run Code Online (Sandbox Code Playgroud)

当我们想要将对象视为函数时,有许多用例.最常见的情况是工厂模式.我们可以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) 
Run Code Online (Sandbox Code Playgroud)

因此,apply方法只是缩小Scala中函数和对象之间差距的一种方便方法.

  • 案例类在这里值得一提.案例类方便,自动且无形地将"apply"和"unapply"方法添加到类的伴随对象(以及其他内容)中.因此,定义一个只有一行的类,例如`case class Car(make:String,model:String,year:Short,color:String)`,可以通过以下方式生成Car类的新对象:`val myCar =汽车( "大众", "高尔夫",1999年, "蓝")`.这是`Car.apply(...)`的简写 (4认同)
  • `每个对象都可以被视为一个函数,只要它有 apply 方法` - 现在就说得通了。 (3认同)

Nic*_*las 47

它来自于您经常想要某些东西应用于对象的想法.更准确的例子是工厂之一.如果您有工厂,则需要参数应用于它以创建对象.

斯卡拉家伙认为,在许多情况下会发生这种情况,因此有一个快捷方式可以调用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)
Run Code Online (Sandbox Code Playgroud)

它通常用在伴侣对象中,为类或特征提供一个很好的工厂方法,这里有一个例子:

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
  }
}
Run Code Online (Sandbox Code Playgroud)

从scala标准库中,您可以看一下如何scala.collection.Seq实现:Seq是一个特性,因此new Seq(1, 2)不会编译,但是由于伴随对象和apply,您可以调用Seq(1, 2)并且伴随对象选择实现.


Tom*_*čka 10

TLDR 适用于来自以下国家/地区的用户c++

它只是( )括号运算符的重载

所以在斯卡拉:

class X {
   def apply(param1: Int, param2: Int, param3: Int) : Int = {
     // Do something
   }
}
Run Code Online (Sandbox Code Playgroud)

与c++中的相同:

class X {
   def apply(param1: Int, param2: Int, param3: Int) : Int = {
     // Do something
   }
}
Run Code Online (Sandbox Code Playgroud)


sdi*_*h94 8

对于那些想要快速阅读的人来说,这是一个小例子

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


} 
Run Code Online (Sandbox Code Playgroud)

产量

greeter-1正在使用消息hello进行实例化

greeter-2正在使用消息世界进行实例化

  • g2的消息正确吗?这实际上是在实例化时发生的,还是实际上在实例化之后发生的(即使是延迟实例化的)? (2认同)