Предположим, у меня есть простой класс case, который упаковывает целые числа, и метод более высокого порядка, который принимает функцию, передающую целые числа в упаковщики.
case class Wrapper(x :Int)
def higherOrder(f : Int => Wrapper) = println(f(42))
Затем я могу вызвать функцию более высокого порядка, передавсгенерированная функция применения оболочки.Удивительно, но я также могу просто указать имя оболочки.
higherOrder(Wrapper.apply) // okay
higherOrder(Wrapper) // okay, wow!
Это действительно круто.Это позволяет нам рассматривать имя класса case как функцию, которая способствует выразительным абстракциям.Пример этой крутости смотрите в ответе здесь. Что означает «абстракция поверх»?
Теперь предположим, что мой класс case недостаточно мощный, и вместо этого мне нужно создать экстрактор.В качестве сценария с умеренно надуманным сценарием, скажем, мне нужно иметь возможность сопоставления с образцом для строк, которые разбираются в целые числа.
// Replace Wrapper case class with an extractor
object Wrapper {
def apply(x :Int) = new Wrapper(x)
def unapply(s :String) :Option[Wrapper] = {
// details elided
}
}
class Wrapper(x :Int) {
override def toString = "Wrapper(" + x + ")"
// other methods elided
}
При этом изменении я все еще могу передать Wrapper.apply в свою функцию более высокого порядка,но передача только Обертки больше не работает.
higherOrder(Wrapper.apply) // still okay
higherOrder(Wrapper) // DOES NOT COMPILE
^^^^^^^
// type mismatch; found : Wrapper.type (with underlying type Wrapper)
// required: (Int) => Wrapper
Ой!Вот почему эта асимметрия вызывает беспокойство.Совет Одерского, Ложки и Веннерса (Программирование на Scala, стр. 500) гласит:
Вы всегда можете начать с классов дел, а затем, если возникнет такая необходимость, перейти на экстракторы.Поскольку шаблоны для экстракторов и шаблоны для классов дел в Scala выглядят одинаково, сопоставления с образцами в ваших клиентах будут продолжать работать.
Совершенно верно, конечно, но мы сломаем наших клиентов, если онииспользуя имена классов в качестве функций.И поскольку это позволяет использовать мощные абстракции, некоторые наверняка это сделают.
Итак, передавая их в функции более высокого порядка, как мы можем заставить экстракторы вести себя так же, как классы case?