В Scala есть концепция списков параметров, где метод может принимать более одного. Однако это также позволяет для удобства опускать пустые списки параметров терминала. Так
f
f()
f()()
все может быть одно и то же - вы не узнаете, пока не посмотрите на f
. Работа параметра по имени заключается в задержке выполнения блока кода. Теперь формально, если мы имеем
def f0: String = "salmon"
def f1(): String = "herring"
def f2()(): String = "halibut"
тогда вы ожидаете, что f0
будет соответствовать параметру по имени, а другие - нет, если они будут преобразованы в функцию. В частности, вы ожидаете
f0 <==> => String
f1 <==> () => String
f2 <==> () => () => String
при преобразовании. Посмотрим, что на самом деле происходит при запросе через f _
:
scala> f0 _
res4: () => String = <function0>
scala> f1 _
res5: () => String = <function0>
scala> f2 _
res6: () => () => String = <function0>
Ну что ж; f0
фактически преобразуется в функцию с одним пустым блоком параметров вместо нуля (так выглядит параметр по имени). Итак, получается, что ваш параметр по имени вообще не преобразует ваш метод в функцию — сигнатуры типов не будут совпадать!
Поэтому вместо этого он рассуждает так:
// I need a code block that returns a long
nanoTime // Wait, there is no nanoTime exactly
nanoTime() // Aha, that works! Must have meant that
: => { nanoTime() } // There, nicely packaged.
Причина, по которой вы не видите разницы, заключается в том, что для того, чтобы вернуть Long
, параметр по имени уже заполняет отсутствующее ()
, но затем оборачивает все это в блок кода для последующего выполнения.
(Заметьте также, что параметры по имени на самом деле просто Function0
под капотом, то есть x: => A
на самом деле x: () => A
, а штука с "нулевыми блоками параметров" - это просто фикция компилятора. На самом деле, все Блоки параметров — это фикция компилятора — JVM знает только об одном списке параметров, и именно эта фикция отсутствия блоков в сочетании с фификом «кто-заботится-о-пустых скобках» приводит к наблюдаемому поведению.)
Если вы запрашиваете функцию из пустого блока параметров, все работает следующим образом:
def printF(f: () => String) = println(f())
scala> printF(f0)
<console>:23: error: type mismatch;
found : String
required: () => String
printF(f0)
^
scala> printF(f1)
herring
scala> printF(f2)
<console>:23: error: type mismatch;
found : () => String
required: String
printF(f2)
scala> printF(f2())
halibut
где теперь скобки do имеют значение, потому что компилятор пытается сопоставить сигнатуру метода с сигнатурой функции. Особые случаи ситуации с параметром по имени больше не применяются.
person
Rex Kerr
schedule
20.01.2013
{() => x}
и{() => x()}
можно просмотреть в качестве эквивалентных прокси, когдаx
эквивалентноx()
.) - person   schedule 21.01.2013()
, как это было бы для функции с нулевым аргументом. - person Randall Schulz   schedule 21.01.2013