Вы правы; 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
методом, называемым ::
, который профессор Одерски старается хранить отдельно, чтобы максимизировать понимание читателя.
Надеюсь, это поможет.