Обновлено после ответа @ IttayD:
Сценарий 1 на Eclipse правильный, вы поймете, почему ниже.Сценарий 2 - явно ошибка Eclipse.ScalaIDE на Eclipse известен своей сломленностью.Я бы не стал доверять (или использовать это).При необходимости используйте плагин Intellij IDEA Scala.
Ответ на оба ваших вопроса заключается в том, что {}
- это блок, который возвращает тип возвращаемого значения последнего оператора.Это точно так же, как схема (begin)
или Common Lisp (progn)
.Когда у вас есть:
scala> def takesFunct(f: => Unit)
{
val b = f
}
takesFunct: (f: => Unit)Unit
scala> val funct = {println("Calling funct")}
Calling funct
funct: Unit = ()
scala> takesFunct(funct)
// No Output
funct
, RHS уже была с нетерпением оценена и вернула значение ()
типа Unit
в функцию.Применение уже вычисленного значения к функции вызова по имени и использование его в теле не вызывает переоценки, поскольку значение уже является листом.
Дальнейшее обновление:
def takesFunct(f: => Unit)
имеет по существу ту же семантику, что и
def takesFunct(f: () => Unit)
, которая известна как потоковая или отложенная оценка в определенных кругах.Есть одно существенное отличие, которое заключается в том, как вы вызываете предоставленный аргумент.В последнем случае, чтобы получить значение из f
, вы должны вызвать его как таковое - то есть f()
.В первом случае f
является ленивым выражением , которое оценивается как значение, когда оно впервые упоминается как таковое, следовательно, call-by-name .Вы можете думать о синтаксисе f: => Unit
как о способе автоматической упаковки любого выражения, которое вы предоставляете в контейнере {}
.Содержимое которого извлекается при использовании следующим образом:
scala> val a = { 1 } // 1 wrapped in {}, and retrieved when assigned to a
a: Int = 1
А как насчет этого?
scala> takesFunct({println("Calling funct")})
Calling funct
Это потому, что теперь вы создаете блок на месте, который привязан кпараметр функции f
, и он оценивается только при использовании его в val b = f
.Давайте сделаем еще один эксперимент:
scala> takesFunct(println("Calling funct"))
Calling funct
Почему вы спрашиваете?Потому что println(...)
был обернут в {}
, который связан с f
.Ссылка f
извлекает значение внутри контейнера, которое равно println(...)
, то есть ():Unit
.В предыдущем примере f
был связан с { { println(...) } }
, что совпадает с { println(...) }
, поэтому вы получите тот же результат.На самом деле вы можете вкладывать {}
на неопределенный срок и все равно получать обратно одно и то же.Единственное отличие состоит в том, что ручное указание {}
позволяет вам помещать несколько операторов внутри так:
scala> takesFunct({ println("hello"); println("world") })
hello
world
Надеюсь, это поможет.