scalabook
Eta расширение
Если посмотреть на Scaladoc для метода map
в классах коллекций Scala, то можно увидеть, что метод определен для приема функции:
def map[B](f: (A) => B): List[B] -----------
Действительно, в Scaladoc сказано: "f
— это функция, применяемая к каждому элементу".
Но, несмотря на это, каким-то образом в map
можно передать метод, и он все еще работает:
def times10(i: Int) = i * 10List(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 2val 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, чтобы быть почти полностью бесшовной
Ссылки: