Какое правило для круглых скобок при вызове метода 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.
4 ответа
Если метод определен как
def toList = { /* something */ }
тогда оно должно называться
object.toList
без лишних скобок. Мы говорим, что этот метод имеет нулевые списки параметров.
Мы могли бы также определить список параметров, но ничего не помещать в него:
def toList() = { /* something */ }
Теперь мы можем позвонить любому из
object.toList()
object.toList
так как Scala позволяет ярлык опускать скобки при вызове метода.
Что касается JVM, то нет разницы между первым определением ("списки нулевых параметров") и вторым ("один пустой список параметров"). Но Скала проводит различие. Является ли это хорошая идея или нет, это вопрос спорный, но мотивация может быть яснее, когда вы понимаете, что мы можем также
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
,
Ваша вторая строка фактически интерпретируется как
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
Позвольте мне ответить с точки зрения стиля Scala.
Руководство по стилю Scala говорит...
Опускайте пустые скобки, используйте только тогда, когда у рассматриваемого метода нет побочных эффектов (чисто функциональный). Другими словами, было бы приемлемо опустить круглые скобки при вызове queue.size, но не при вызове println().
Религиозное соблюдение этого соглашения значительно улучшит читабельность кода и значительно упростит понимание самой основной операции любого данного метода. Не поддавайтесь искушению опустить скобки, просто чтобы сохранить два символа!
11 лет спустя... ИсключениеNot enough arguments for method apply: (n: Int)Int in trait LinearSeqOptimized
сообщение дает вам подсказку. Проверка документов для LinearSeqOps.html#apply(n:Int):A:
def apply(n: Int): A
Получить элемент по указанному индексу.
The toList
вArray
не принимает никаких аргументов [см. Array:toList docs] и преобразует его вl: List[Int]
, который являетсяLinearSeqOps
черта:
val l = Array(1,2,3).toList // l: List[Int] = List(1, 2, 3)
Есть много способов позвонитьapply(0)
в спискеl
чтобы получить элемент по индексу0
. Все они делают одно и то же :
var el1 = l.apply(0) // el1: Int = 1
el1 = l(0) // el1: Int = 1
el1 = Array(1,2,3).toList.apply(0) // el1: Int = 1
el1 = Array(1,2,3).toList(0) // el1: Int = 1
Но если мы не обеспечимInt
аргументapply(n: Int)
, код завершится ошибкой. Одни и те же варианты будут давать одну и ту же ошибку :
el1 = Array(1,2,3).toList() // not enough arguments for method apply: (n: Int)
el1 = Array(1,2,3).toList.apply() // not enough arguments for method apply: (n: Int)
el1 = l.apply() // not enough arguments for method apply: (n: Int)
el1 = l() // not enough arguments for method apply: (n: Int)