Ответ 1
1) Это более удобно использовать, особенно внутри DSL:
def printAndGet[T](f: => T) = {
val res = f
println(res + " printed")
res
}
scala> :paste
// Entering paste mode (ctrl-D to finish)
val k = printAndGet {
val a = 5
5 * a
}
// Exiting paste mode, now interpreting.
25 printed
k: Int = 25
2) => T
может быть только параметром метода или функции. И фактически => T
и () => T
не взаимозаменяемы:
scala> def aaa(f: => String) = f
aaa: (f: => String)String
scala> val a: Function1[() => String, String] = aaa _
<console>:8: error: type mismatch;
found : (=> String) => String
required: (() => String) => String
val a: Function1[() => String, String] = aaa _
^
Благодаря @som-snytt, сделайте следующее:
scala> object O { def f(i: Int) = i; def f(i: => Int) = i + 1 }
defined object O
scala> O.f(5)
res12: Int = 5
scala> O.f(5: (=> Int))
<console>:1: error: no by-name parameter type allowed here
O.f(5: (=> Int))
^
Даже это должно работать, если оно компилируется, но оно не работает (scala 2.11.2, 2.11.5 REPL просто сбой):
scala> val k: (=> Int) => Int = O.f _
k: (=> Int) => Int = <function1>
scala> k(5) //should be 6
res18: Int = 5 //WTF?
Последний выглядит как ошибка
3) Не совсем, если вы хотите того же, просто преобразуйте => T
в () => T
:
scala> def aaa(f: => String) = {f _}
aaa: (f: => String)() => String
Bytecode также может отличаться. Например, компилятор будет скорее иметь встроенный код из => T
без генерации лямбда для него. Итак, главное отличие состоит в том, что () => T
на самом деле является объектом (гражданин первого класса), => T
не является.
4) см. 1, но иногда вам может потребоваться убедиться, что пользователь знает, что вычисление может быть отложено - () => T
лучше.
5) Это часть сигнатуры типа, просто посмотрите на eta-расширение:
scala> def aaa(f: => String) = {f}
aaa: (f: => String)String
scala> aaa _ //convert method into a function
res7: (=> String) => String = <function1>
scala> val a: ( => String) => String = aaa _
a: (=> String) => String = <function1>
Однако scala не распознает его как независимый тип:
scala> val a: Function1[( => String), String] = aaa _
<console>:1: error: no by-name parameter type allowed here
val a: Function1[( => String), String] = aaa _
^