Что такое функция применения в Scala? - PullRequest
284 голосов
/ 16 марта 2012

Я никогда не понимал этого из придуманных существительных и глагольных существительных (класс AddTwo имеет apply, который добавляет два!) Примеров.

Я понимаю, что это синтаксический сахар, поэтому (я понял из контекста) он должен был быть разработан, чтобы сделать некоторый код более интуитивным.

Какое значение имеет класс с функцией apply? Для чего он используется и в каких целях он делает код лучше (немаршалинг, глаголы существительными и т. Д.)?

как это помогает при использовании в объекте-компаньоне?

Ответы [ 3 ]

590 голосов
/ 16 марта 2012

У математиков есть свои собственные маленькие забавные способы, поэтому вместо того, чтобы говорить «тогда мы вызываем функцию 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

Поскольку в Scala все является объектом, 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) каждый раз, когда вы хотите выполнить функцию, представленную как объект, является объектно-ориентированным способом, но добавит много беспорядка в код без добавления дополнительной информации, и было бы неплохо иметь возможность используйте более стандартные обозначения, такие как 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 

Есть много случаев использования, когда мы хотим рассматривать объект как функцию. Наиболее распространенным сценарием является фабричный шаблон . Вместо того, чтобы добавлять беспорядок в код, используя фабричный метод, мы можем 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.

46 голосов
/ 16 марта 2012

Это исходит из того, что вы часто хотите применить что-то к объекту. Более точный пример - один из заводов. Если у вас есть фабрика, вы хотите применить параметр к ней, чтобы создать объект.

Ребята из 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) не будет компилироваться, но благодаря объекту-компаньону и apply вы можете вызвать Seq(1, 2) и реализация выбирается объектом-компаньоном.

7 голосов
/ 17 августа 2017

Вот небольшой пример для тех, кто хочет быстро просмотреть

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


} 

output

Greeter-1 создается с сообщением привет

Greeter-2 создается в мире сообщений

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...