Просто замеченный интересная возможность инициализировать блоки кода в Scala для старшего разряда функционирует, такие как foreach или карта:
(1 to 3) map {
val t = 5
i => i * 5
}
(1 to 3) foreach {
val line = Console.readLine
i => println(line)
}
Разве это - некоторая зарегистрированная функция, или я должен избежать таких конструкций? Я мог вообразить, блок "инициализации" входит в конструктора, и само закрытие становится применением () метод?
Спасибо Кусочек для исходного Вопроса (http://extrabright.com/blog/2010/07/10/scala-question-regarding-readline)
Хотя используемые функции не являются редкостью, я признаю, что это довольно странная комбинация функций. Основная хитрость заключается в том, что любой блок в Scala - это выражение, тип которого совпадает с типом последнего выражения в блоке. Если последнее выражение является функцией, это означает, что блок имеет функциональный тип, и поэтому может быть использован в качестве аргумента в "map" или "foreach". В этих случаях происходит так: когда вызывается "map" или "foreach", блок оценивается. Блок оценивается в функцию ( i=> i*5 в первом случае ), и эта функция затем отображается на диапазон.
Одно из возможных применений этой конструкции заключается в том, что блок определяет изменяемые переменные, а результирующая функция изменяет переменные при каждом вызове. Переменные будут инициализированы один раз, закрыты функцией, и их значения будут обновляться при каждом вызове функции.
Например, вот несколько неожиданный способ вычисления первых 6 факториалов чисел
(1 to 6) map {
var total = 1
i => {total *= i;total}
}
(BTW, извините за использование факториала в качестве примера. Либо это, либо фибоначчи. Функциональный Прогаммирование правил Гильдии. Если у вас с этим проблемы, обратитесь к ребятам в зале.)
Менее важная причина, по которой блок возвращает функцию, - это определение вспомогательных функций в начале блока. Например, если бы ваш второй пример был вместо
(1 to 3) foreach {
def line = Console.readLine
i => println(line)
}
В результате три строки были бы прочитаны и повторены по одному разу, в то время как в вашем примере строка была прочитана один раз и повторена три раза.
Во-первых, в комментарии оригинального блога "Scala Question Regarding readLine" упоминается
The "
line
" is a value and cannot be executed, it is assigned only once from the result of the execution of the "Console.readLine
" method.
Он используется менее трех раз в вашем закрытии.
Но если вы определите его как метод, он будет выполнен три раза:
(1 to 3) foreach {
def line = Console.readLine
i => println(line)
}
В блоге Scala для беженцев от Java Часть 6: Переход от Java есть интересный раздел о функциях высшего порядка, в том числе:
Scala обеспечивает еще большую гибкость в синтаксисе для этих функций высшего порядка.
В вызове iterate мы создаем целый анонимный метод только для того, чтобы сделать еще один вызов методаprintln(String)
.
Учитывая, чтоprintln(String)
сам является методом, который принимаетString
и возвращаетUnit
, можно подумать, что мы можем немного сжать это. Оказывается, можно:
iterate(a, println)
Опустив круглые скобки и указав только имя метода, мы сообщаем компилятору Scala, что хотим использовать
println
в качестве функционального значения, передав его методуiterate
.
Таким образом, вместо того чтобы создавать новый метод только для обработки одного набора вызовов, мы передаем старый метод, который уже делает то, что нам нужно.
Этот паттерн часто встречается в C и C++. Фактически, синтаксис для передачи функции в качестве функционального значения точно такой же. Похоже, что некоторые вещи никогда не меняются...