Использование нового с финальным классом Scala - PullRequest
5 голосов
/ 15 декабря 2011

В главе 22 книги «Программирование в Scala» класс :: (cons) определен как

final case class ::[T](hd: T, tl: List[T]) extends List[T] {
  //...
}

Метод :: в классе List определяется следующим образом:

def ::[U >: T](x: U): List[U] = new scala.::(x, this)

Почему new требуется для создания экземпляра finalcaseclass ::? Это чисто для устранения неоднозначности?

Ответы [ 2 ]

6 голосов
/ 15 декабря 2011

С классами case вы автоматически получаете сопутствующий объект, чей метод apply вызывает конструктор, так же, как вы можете сделать это с обычным классом:

class Foo(val value: Int) 
object Foo { def apply(value: Int) = new Foo(value) }

val x = new Foo(42)  //
val y = Foo(42)      // both work the same

Вы можете создавать экземпляры классов дел с помощью new, если хотите. Теоретически он может быть немного быстрее, потому что он не должен проходить через метод apply объекта-компаньона, но я попробовал быстрый тест и не увидел абсолютно никакой разницы в производительности, поэтому я думаю, что он оптимизирован компилятором или просто неизмеримо небольшая разница по сравнению с реальной конструкцией.

Так что я не думаю, что new в приведенном вами примере имеет какое-либо значение и с тем же успехом мог бы быть опущен.

3 голосов
/ 15 декабря 2011

Вы правы; new не является обязательным. Они могли бы также определить метод экземпляра List#:: следующим образом:

def ::[U >: T](x: U): List[U] = scala.::(x, this)

(Обратите внимание, что у нас есть:

type :: = collection.immutable.::
val  :: = collection.immutable.::

определено в объекте пакета scala; во-первых, почему ваш new scala.::(x, this) работает, а во-вторых, почему мой scala.::(x, this) работает.)

Форма, которую использует библиотека , вызывает конструктор напрямую, как и ваш. Альтернатива вызывает метод apply синтетического сопутствующего объекта, сгенерированного для класса ::, который в любом случае просто вызывает конструктор. Возможно, вызов конструктора считался более понятным или более эффективным? (Повышение эффективности должно быть почти равно нулю, поскольку, если компилятор не встроит вызов apply, JVM сделает это.) Полагаю, наиболее компактная форма:

def ::[U >: T](x: U) = ::(x, this)

может быть ошибочно принято за какой-то дурацкий (то есть невозможный) вид рекурсивного вызова, и, во всяком случае, размывает различие между классом, называемым ::, и List методом, называемым ::, который профессор Одерски старается хранить отдельно, чтобы максимизировать понимание читателя.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...