Что такое функция применения в 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()
метод.