Почему сопутствующие объекты класса case расширяют FunctionN? - PullRequest
38 голосов
/ 16 июня 2010

Когда вы создаете класс case, компилятор создает соответствующий объект-компаньон с несколькими полезностями класса case: метод фабрики apply, соответствующий первичному конструктору, equals, hashCode и copy.

Как ни странно, этот сгенерированный объект расширяет FunctionN.

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) 

Ответы [ 4 ]

48 голосов
/ 16 июня 2010

Причина, по которой сопутствующие объекты класса case реализуют FunctionN, заключается в том, что ранее классы case генерировали класс и метод фабрики, а не объект-компаньон. Когда мы добавили экстракторы в Scala, было больше смысла превратить фабричный метод в полноценный объект-компаньон с методами apply и unapply. Но затем, поскольку фабричный метод действительно соответствовал FunctionN, объект-компаньон также должен был соответствовать.

[Edit] Тем не менее, было бы целесообразно, чтобы сопутствующие объекты отображались как их собственные имена, а не как "функции"

11 голосов
/ 16 июня 2010

Ну, учитывая, что target.apply(a1, a2, a3 ... aN) в Scala:

  1. может быть засахарено target(a1, a2, a3 ... aN)
  2. - это метод, который должен быть реализован 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)
}

Так что сложение кажется мне естественным (я не уверен, почему оно кажется вам "странным"?). Что касается того, действительно ли он добавил что-нибудь; ну, это для кого-то умнее меня!

11 голосов
/ 16 июня 2010

Помимо ответа 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))
5 голосов
/ 16 июня 2010
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!)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...