Каково правило для скобок в вызове метода Scala?

Не toList метод, который преобразует что-то в список?

Если да, то почему я не могу использовать скобки с ним? Я должен упустить что-то более фундаментальное здесь.

Вот пример:

val l = Array(1,2,3).toList // works fine

val l = Array(1,2,3).toList() // gives the error below

Недостаточно аргументов для метода: (n: Int) Int в признаке LinearSeqOptimized. Неопределенный параметр значения n.

Ответ 1

Если метод определен как

def toList = { /* something */ }

то он должен быть вызван как

object.toList

без дополнительных скобок. Мы говорим, что этот метод имеет нулевые списки параметров.

Мы также можем определить список параметров, но ничего не добавили в него:

def toList() = { /* something */ }

Теперь мы можем назвать любой из

object.toList()
object.toList

так как Scala разрешает ярлык опускания круглых скобок при вызове метода.

Что касается JVM, то нет никакой разницы между первым определением ( "списки нулевых параметров" ) и вторым ( "один пустой список параметров" ). Но Scala поддерживает различие. Является ли это хорошая идея или нет, это вопрос спорный, но мотивация может быть яснее, когда вы понимаете, что мы можем также

def toList()() = { /* something */ }

который известен как два пустых списка параметров, а затем вызывает любой из

object.toList()()
object.toList()
object.toList

и теперь, если мы должны преобразовать это в функцию, мы будем набирать его как

() => () => T   /* T is the return value of the something */

тогда как второе определение будет

() => T

который явно отличается концептуально, даже если вы практически используете его одинаково (ничего не ставьте и рано или поздно выходите из T).

Во всяком случае, toList не нуждается в каких-либо параметрах, а стандарт Scala должен оставить без параметров, если метод не изменяет сам объект (а не просто что-то возвращает), поэтому он def toList без каких-либо парен после этого. И поэтому вы можете назвать его только как object.toList.

Ответ 2

Ваша вторая строка фактически интерпретируется как

val l = Array(1,2,3).toList.apply()

поскольку foo(x) является "магическим" синтаксисом для foo.apply(x).

Вот почему компилятор жалуется на "недостаточно аргументов", поскольку метод apply в списках принимает один аргумент.

Таким образом, вы можете написать, например:

scala> val i = Array(1, 2, 3).toList(1)
i: Int = 2

Ответ 3

Позвольте мне ответить с точки зрения стиля кодирования Scala.

Scala руководство по стилю говорит...

Опустить пустую скобку, использовать ее только тогда, когда рассматриваемый метод не имеет побочных эффектов (чисто функциональных). Другими словами, было бы приемлемо опускать круглые скобки при вызове queue.size, но не при вызове println().

Религиозное наблюдение за этим соглашением значительно улучшит читаемость кода и значительно упростит понимание с первого взгляда самой базовой операции любого данного метода. Сопротивляйтесь стремлению опустить скобки, просто чтобы сохранить два символа!