Приложение с частичной функцией преждевременно запускает кодовый блок при использовании подчеркивания - PullRequest
9 голосов
/ 07 февраля 2011

Дано:

def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") } 

Я могу вызвать его с помощью:

save("test")(true) -> running f
save("test")(false) -> not running f
save(throw new RuntimeException("boom!"))(false) -> not running f
save(throw new RuntimeException("boom!"))(true) -> running f and then exception thrown

Вот странное поведение с частичным применением:

save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected
save(throw new RuntimeException("boom!")) _ -> exception thrown

Кодовый блок оцениваетсянемедленно, не будучи переданным как функция.В чем разница между двумя приведенными выше утверждениями?

Ответы [ 2 ]

3 голосов
/ 07 февраля 2011

Первый случай ,

save(throw new RuntimeException("boom!")) _ 

Согласно "Scala Reference" (§6.7), вместо списка аргументов используется завершающее подчеркивание, ивыражение преобразуется в

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))

, где первый аргумент def save немедленно вычисляется.

Выражение e _ корректно сформировано, если e имеет тип метода или еслиe является параметром вызова по имени.Если e - метод с параметрами, e _ представляет e, преобразованный в тип функции путем расширения eta (§6.26.5).Если e является параметром без параметров или параметром вызова по имени типа => T, e _ представляет функцию типа () => T, которая оценивает e при применении к пустому списку параметров ().

Чтобы все работало так, как вы ожидаете, требуются некоторые модификации:

scala> def save(f:() => Any)(run:Boolean) { if (run) { println("running f"); f() } else println("not running f") }
save: (f: () => Any)(run: Boolean)Unit

scala> val f = save(() => throw new RuntimeException("boom!")) _
f: (Boolean) => Unit = <function1>

scala> f(true)
running f
java.lang.RuntimeException: boom!
        at $anonfun$1.apply(<console>:6)

Второй случай ,

save(throw new RuntimeException("boom!"))(_)

Согласно «Scala Reference» (§6.23), когда в качестве замены аргумента используется заполнитель, выражение преобразуется в

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))(_)
0 голосов
/ 01 июня 2012

Поведение параметров вызова по имени при расширении eta в настоящее время рассматривается, см. эту ошибку .Ваш код работает так, как вы ожидаете (то есть строка save(throw new RuntimeException("boom!")) _ возвращает функцию без исключения) с недавними ночными сборками 2.10.Давайте посмотрим, останется ли он до релиза!

См. Также этот вопрос для связанного вопроса по общему случаю расширения eta, не включающего вызов по имени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...