Почему объекты-компаньоны класса класса расширяют функциональность?
При создании класса case компилятор создает соответствующий сопутствующий объект с несколькими достоинствами класса case: метод apply
factory, соответствующий основному конструктору, equals
, hashCode
и copy
.
Как ни странно, этот сгенерированный объект расширяет функциональность.
scala> case class A(a: Int)
defined class A
scala> A: (Int => A)
res0: (Int) => A = <function1>
Это только в том случае, если:
- Не указано вручную сопутствующий объект
- Существует только один список параметров
- Нет аргументов типа
- Класс case не является абстрактным.
Похоже, что это было добавлено около двух лет назад. Последнее воплощение здесь.
Кто-нибудь использует это или знает, почему он был добавлен? Он немного увеличивает размер сгенерированного байт-кода со статическими методами пересылки и появляется в методе #toString()
для сопутствующих объектов:
scala> case class A()
defined class A
scala> A.toString
res12: java.lang.String = <function0>
UPDATE
Созданные вручную объекты с помощью одного метода apply
автоматически не рассматриваются как FunctionN
:
object HasApply {
def apply(a: Int) = 1
}
val i = HasApply(1)
// fails
// HasApply: (Int => Int)
Ответы
Ответ 1
Причина, по которой объекты класса класса класса реализуют FunctionN, заключается в том, что раньше классы case генерировали класс и метод factory, а не объект-компаньон. Когда мы добавили экстракторы в Scala, было более целесообразно превратить метод factory в полный объект-компаньон с методами применения и неприменения. Но тогда, поскольку метод factory соответствовал FunctionN, тоже должен был соответствовать объект-компаньон.
[Edit] Как было сказано, было бы разумно, чтобы объекты-компаньоны отображались как их собственное имя, а не как "функция"
Ответ 2
Хорошо, учитывая, что target.apply(a1, a2, a3 ... aN)
в Scala:
- можно закрепить
target(a1, a2, a3 ... aN)
- - это метод, который должен быть реализован
FunctionN
кажется естественным, что объект-компаньон:
object MyClass {
def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}
действительно:
object MyClass extends FunctionN[A1, ... , AN, MyClass]{
def apply(a1 : A1, ... aN: AN) = new MyClass(a1, ..., aN)
}
Итак, добавление кажется мне естественным (я не уверен, почему это кажется "странным" для вас?). Что касается того, действительно ли это что-то добавило; ну, это для кого-то умнее меня!
Ответ 3
Помимо ответа oxbow_lakes о его естественности, часто бывает полезно иметь конструкторы в качестве первоклассных функций, особенно в сочетании с функциями Scala для более высоких порядков. Для (тривиального) примера,
scala> case class Foo(i : Int)
defined class Foo
scala> List(1, 2, 3) map Foo
res0: List[Foo] = List(Foo(1), Foo(2), Foo(3))
Ответ 4
Welcome to Scala version 2.8.0.RC3 (Java HotSpot(TM) Client VM, Java 1.6.0_20).
scala> case class CC3(i: Int, b: Boolean, s: String)
defined class CC3
scala> CC3
res0: CC3.type = <function3>
scala> CC3.apply(1, true, "boo!")
res1: CC3 = CC3(1,true,boo!)
scala> CC3(1, true, "boo!")
res2: CC3 = CC3(1,true,boo!)