scala foreach и инициализаторы карты

Просто замеченный интересная возможность инициализировать блоки кода в 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)

7
задан niton 22 April 2015 в 00:00
поделиться

2 ответа

Хотя используемые функции не являются редкостью, я признаю, что это довольно странная комбинация функций. Основная хитрость заключается в том, что любой блок в 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)  
}

В результате три строки были бы прочитаны и повторены по одному разу, в то время как в вашем примере строка была прочитана один раз и повторена три раза.

12
ответ дан 6 December 2019 в 19:32
поделиться

Во-первых, в комментарии оригинального блога "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++. Фактически, синтаксис для передачи функции в качестве функционального значения точно такой же. Похоже, что некоторые вещи никогда не меняются...

1
ответ дан 6 December 2019 в 19:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: