Ответ 1
TL;DR
Ответы, полученные до сих пор (@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
, работали, так как без получения значения a for
эквивалентно foreach
!? (Представляя yield
, закончится поведением Map
)
Ответ в коде... Компилятор шаблона добавит ключевое слово yield
к телу for
- проверьте это здесь.:-D
Et voilà, он тоже работает, поскольку созданные вещи в теле for
будут прикреплены к возвращенной последовательности после ее завершения.