Eta расширение
Если посмотреть на Scaladoc для метода map
в классах коллекций Scala, то можно увидеть, что метод определен для приема функции:
def map[B](f: (A) => B): List[B]
-----------
Действительно, в Scaladoc сказано: "f
— это функция, применяемая к каждому элементу".
Но, несмотря на это, каким-то образом в map
можно передать метод, и он все еще работает:
def times10(i: Int) = i * 10
List(1, 2, 3).map(times10)
// res0: List[Int] = List(10, 20, 30)
Как это работает? Как можно передать метод в map
, который ожидает функцию?
Технология, стоящая за этим, известна как Eta Expansion. Она преобразует выражение типа метода в эквивалентное выражение типа функции, и делает это легко и незаметно.
Различия между методами и функциями
Исторически методы были частью определения класса, хотя в Scala 3 методы могут быть вне классов, такие как определения верхнего уровня и методы расширения.
В отличие от методов, функции сами по себе являются полноценными объектами, что делает их объектами первого класса.
Их синтаксис также отличается. В этом примере показано, как задать метод и функцию, которые выполняют одну и ту же задачу, определяя, является ли заданное целое число четным:
def isEvenMethod(i: Int) = i % 2 == 0 // метод
val isEvenFunction = (i: Int) => i % 2 == 0 // функция
Функция действительно является объектом, поэтому ее можно использовать так же, как и любую другую переменную, например, помещая в список:
val functions = List(isEvenFunction)
И наоборот, технически метод не является объектом, поэтому в Scala 2 метод нельзя было поместить в список, по крайней мере, напрямую, как показано в этом примере:
// В этом примере показано сообщение об ошибке в Scala 2
val methods = List(isEvenMethod)
^
error: missing argument list for method isEvenMethod
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `isEvenMethod _` or `isEvenMethod(_)` instead of `isEvenMethod`.
Как показано в этом сообщении об ошибке, в Scala 2 существует ручной способ преобразования метода в функцию, но важной частью для Scala 3 является то, что технология Eta Expansion улучшена, поэтому теперь, когда попытаться использовать метод в качестве переменной, он просто работает — не нужно самостоятельно выполнять ручное преобразование:
val functions = List(isEvenFunction)
val methods = List(isEvenMethod)
Важно отметить следующее:
- Eta Expansion — технология Scala, позволяющая использовать методы так же, как и функции
- Технология была улучшена в Scala 3, чтобы быть почти полностью бесшовной
Ссылки: