Компилятор Scala сообщает о несоответствии типов для закрытия

У меня есть код ниже:

test("temp") {
    def greeting(func: (String) => Unit, name: String) {
        func(name)
    }

    // Success
    greeting(println(_), "Hello")
    greeting( { case _ => println("" + `_`) },  "Hello")

    // Failed
    greeting(println("" + _), "Hello")
    greeting(println("a"), "Hello")
}

Сообщение об ошибке:

Error:(52, 29) type mismatch;
     found   : Unit
     required: String => Unit
        greeting(println("" + _), "Hello")

Error:(53, 29) type mismatch;
     found   : Unit
     required: String => Unit
        greeting(println("a"), "Hello")
                        ^

Я не очень хорошо это понимаю. В чем разница между println("" + _) и (String) => Unit? и почему println("a") не рассматривается как (String) => Unit, а println(_) обрабатывается?


person user3593261    schedule 05.05.2016    source источник


Ответы (1)


Утверждение 1

greeting(println(_), "Hello") // placeholder syntax

Выше приведена краткая форма литерала функции, которая называется синтаксисом-заполнителем. Он расширяется следующим образом:

greeting(x => println(x), "Hello")

Утверждение 2

greeting( { case _ => println("" + `_`) },  "Hello") // wildcard pattern

case _ — шаблон подстановочного знака. Вы не можете использовать _ снова. Если вы хотите использовать предложение case, вы должны использовать сопоставление переменных:

greeting( { case x => println("" + x) },  "Hello")

Утверждения 3 и 4

greeting(println("" + _), "Hello")
greeting(println("a"), "Hello")

Обратите внимание, что "" + _ в println("" + _) сама по себе является анонимной функцией. Итак, println("" + _) считается выражением.

Компилятор обрабатывает как println("" + _), так и println("a") как выражение, а не как функциональный литерал, переданный в качестве параметра. Поэтому сначала он пытается оценить println("" + _) и println("a"), а затем передает результат (Unit) в greeting, отсюда и ошибка компиляции.

person justAbit    schedule 05.05.2016
comment
Спасибо, Судхир, означает ли это, что компилятор ставит приоритет вызова функции выше, чем синтаксис-заполнитель? - person user3593261; 05.05.2016
comment
Пожалуйста, посмотрите мой обновленный ответ, это может развеять ваши сомнения. - person justAbit; 05.05.2016
comment
А как компилятор различает вызов функции или нет? так как println( + ) также имеет внутри. почему это не синтаксис заполнителя? - person user3593261; 05.05.2016
comment
Попробуйте запустить println("" + _) в REPL, получите ответ. - person justAbit; 05.05.2016
comment
В общем, могу ли я подумать, что когда компилятор встречает символы подчеркивания, он всегда будет считать своего владельца замыканием? чтобы его сразу не вызывали? потому что подчеркивания - это место, которое будет заполнено на лету? и, кроме того, символы подчеркивания имеют свою эффективную область действия, которая каким-то образом ограничена симпатиями только для { + _}, поэтому функция println не считается анонимной функцией. Я прав? - person user3593261; 05.05.2016
comment
Закрытие - это другое понятие. Оценка _ немного интересна в println("" + _). Я бы порекомендовал вам прочитать этот ответ: stackoverflow.com/questions/2173373/ - person justAbit; 05.05.2016