Что такое функция применения в Scala?

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

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

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

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

7 ответов

Решение

У математиков есть свои маленькие забавные способы, поэтому вместо того, чтобы говорить "тогда мы вызываем функцию f прохождение x в качестве параметра "как мы, программисты, говорим, они говорят о" применении функции f к его аргументу x".

В математике и информатике Apply - это функция, которая применяет функции к аргументам.
Википедия

apply служит для устранения разрыва между объектно-ориентированной и функциональной парадигмами в Scala. Каждая функция в Scala может быть представлена ​​как объект. Каждая функция также имеет тип OO: например, функция, которая принимает 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] объект. Например, мы можем позвонить 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.

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

Ребята из 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) и реализация выбирается объектом-компаньоном.

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

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


} 

выход

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

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

TLDR для людей из c++

Это просто перегруженный оператор ( )скобки

Итак, в скале:

      class X {
   def apply(param1: Int, param2: Int, param3: Int) : Int = {
     // Do something
   }
}

Это то же самое, что и в С++:

      class X {
   int operator()(int param1, int param2, int param3) {
      // do something
   }
};

1 - Относитесь к функциям как к объектам.

2 - Метод применения похож на __call __ в Python, что позволяет использовать экземпляр данного класса в качестве функции.

Метод применения — это то, что превращает объект в функцию. Желание состоит в том, чтобы иметь возможность использовать синтаксис функций, например:

f(аргументы)

Но Scala имеет как функциональный, так и объектно-ориентированный синтаксис. Тот или иной должен быть основой языка. Scala (по разным причинам) выбирает объектно-ориентированный язык в качестве базовой формы. Это означает, что синтаксис любой функции должен быть переведен в объектно-ориентированный синтаксис.

Вот тут-то и пригодится apply. Любой объект, у которого есть метод apply, можно использовать с синтаксисом:

f(аргументы)

Затем инфраструктура scala преобразует это в

f.применить (аргументы)

f.apply(args) имеет правильный объектно-ориентированный синтаксис. Выполнение этого перевода было бы невозможно, если бы у объекта не было метода применения!

Короче говоря, наличие метода apply в объекте позволяет Scala преобразовать синтаксис: object(args) в синтаксис: object.apply(args). И object.apply(args) находится в форме, которую затем можно выполнить.

К вашему сведению, это означает, что все функции в scala являются объектами. И это также подразумевает, что наличие метода apply делает объект функцией!

См. принятый ответ для получения более подробной информации о том, как функция является объектом, и о трюках, которые можно использовать в результате.

Грубо говоря,

Вы можете просто увидеть это как обычай ()operator. Если класс Xимеет метод, всякий раз, когда вы вызываете X()вы будете звонить в apply()метод.

Другие вопросы по тегам