ТЛ; др
Ответы, данные до сих пор ( @ wbarksdale , @ PlexQ и @ Daniel C. Sobral в комментарии) достаточно хороши, чтобы нацелить проблему описано здесь.
Но им не хватает реального объяснения того, почему исходный код, использующий foreach
, не работает.
Не может работать, потому что foreach
возвращает Unit
.
Концепции игры
Позвольте мне кратко заметить / вспомнить, как работают шаблоны.
Система шаблонов Scala, предоставляемая по умолчанию в Play Framework 2, действительно построена на концепциях FP и, следовательно, использует множество неизменяемых структур и т. Д.
Более того, такой шаблон Scala (скажем, myTemplate.scala.html
) будет скомпилирован в обычный Scala object
, в котором вызывается метод apply
. Эта последняя функция позволяет нам вызывать объект как функцию с некоторыми параметрами (объявленными в первой строке шаблона).
Это object
также опирается на конструкцию, подобную BaseScalaTemplate
, которая построена с помощью выходного форматера (Html). Этот форматер сможет принимать данные (например, String
, Unit
, Seq[Int]
, Map[A,B]
, ...) и преобразовывать их в HTML-код.
Форматирование будет выполняться при использовании _display_
метода BaseScalaTemplate
, который возвращает экземпляр отформатированного вывода . Этот метод отображения будет вызываться в скомпилированном коде файла .scala.html
в теле метода apply
объекта.
Итак, тело может закончиться так:
def apply/*1.2*/(testMap:scala.collection.immutable.Map[String, Int]):play.api.templates.Html =
_display_ {
Seq[Any](
_display_(
Seq[Any](
/*3.2*/testMap/*3.9*/.map/*3.13*/ { e =>
_display_(Seq[Any](_display_(Seq[Any](/*5.3*/e))))
}
)
)
)
}
См? Вызовы _display_
ничего не изменяют, но они скомпонованы таким образом, что их применение само вернет экземпляр отформатированного кода (Html
)!
Это дает нам ключ ...
да бла-бла ... теперь почему?
После этих молний, данных о внутренностях Play, теперь мы можем заняться реальным вопросом: почему, черт возьми, идеологический код Scala, представленный в посте с вопросом, не работает ... читай, ничего не выводит вообще.
Это довольно просто, когда вы используете foreach
на Map
, вы действительно зацикливаете на элементах и адаптируете их к Html. Но эти вычисления не будут использоваться системой шаблонов, потому что они заключены в цикл foreach
. То есть foreach
необходимо использовать, когда для каждого элемента в последовательности требуются побочные эффекты ... И возвращать Unit
, когда это будет сделано.
Поскольку система шаблонов будет пытаться _display_
получить результат foreach
на данном Map
, она просто отобразит / отформатирует Unit
и, таким образом, пустое String
!
В заключение, используйте map
, который вернет новую последовательность, содержащую адаптированные элементы, экземпляр Html
.
Хммм а как насчет for
?
Да, вы правы ... Исходя из сказанного, почему ответы, в которых предлагалось использовать цикл for
, работают, поскольку без значения значение for
эквивалентно foreach
!? (Введение yield
закончится map
-подобным поведением)
Ответ в коде ... Компилятор шаблонов добавит ключевое слово yield
к телу for
- проверьте это здесь . : -D
Et voilà , это тоже работает, так как сгенерированные элементы в теле for
будут присоединены к возвращенной последовательности после ее завершения.