玩!Framework 2.0 - 在 Scala 模板中循环遍历地图? [英] Play! Framework 2.0 - Looping through a map in a scala template?
问题描述
我有一个表示目录的地图,它包含 Chapter
键和 List[Section]
值.现在我正试图在我的模板中循环这个:
I have a map representing a table of contents, it contains Chapter
keys and List[Section]
values. Right now I am trying to loop through this in my template like this:
<dl>
@table_of_contents.foreach((e) => {
<dt>
@e._1.title
</dt>
for(section <- e._2){
<dd>
@section.title
</dd>
}
})
</dl>
我目前在
中没有任何输出.
I currently get no output in the <dl>
however.
我在模板顶部添加了一个 println(table_of_contents)
语句,以确保地图确实有数据并打印出来:
I added a println(table_of_contents)
statement to the top of the template to ensure that the map did in fact have data and it printed:
{models.Chapter@1=BeanList size[4] hasMoreRows[false] list[models.Section@1, models.Section@2, models.Section@3, models.Section@4], models.Chapter@2=BeanList size[0] hasMoreRows[false] list[]}
也许我需要使用命令式风格?
perhaps I need to use an imperative style?
更新:
仍在研究这个……编译这个变体但没有输出.
Still working on this... got this variation to compile but no output.
<dl>
@table_of_contents.foreach{case(a, b) => {
<dt>
@a.title
</dt>
@displaySections(b)
}}
</dl>
...
@displaySections(sections: List[Section]) = {
@for(a_section <- sections) {
<dd>@a_section.title</li>
}
}
推荐答案
tl;dr
到目前为止给出的答案(来自 @wbarksdale、@PlexQ 和 @Daniel C. Sobral 在评论中) 足以解决此处描述的问题.
The answers given so far (by @wbarksdale, @PlexQ and @Daniel C. Sobral in a comment) are good enough to target the problem described here.
但是他们没有真正解释为什么使用 foreach
的初始代码不起作用.
But they're missing a real explanation about why the initial code, using foreach
, doesn't work.
它无法工作,因为foreach
返回Unit
.
It cannot work because foreach
returns Unit
.
游戏概念
让我快速说明/回忆一下模板的工作原理.
Let me give a quick note/recall about how templates work.
Play Framework 2 中默认提供的 Scala 模板系统确实建立在 FP 概念之上,因此它使用了许多不可变结构等.
The Scala templating system provided by default in Play Framework 2 is indeed built upon FP concepts and thus it uses a lot of immutable structures and so forth.
此外,这样的 Scala 模板(比方说 myTemplate.scala.html
)将被编译成一个具有 apply
的常规 Scala object
方法调用.后一个函数使我们能够调用对象作为带有一些参数(在模板的第一行中声明的参数)的函数.
Moreover, such Scala template (let's say myTemplate.scala.html
) will be compiled into a regular Scala object
which has an apply
method called. This latter function enables us to call the object as a function with some parameters (those declared in the first line of the template).
这个 object
也依赖于像 BaseScalaTemplate
使用输出格式化程序 (Html) 构建.这个格式化程序将能够接受一些东西(比如 String
、Unit
、Seq[Int]
、Map[A,B]
, ...) 并将其呈现为 HTML 代码.
This object
is also relying on a construction like BaseScalaTemplate
which is built with an output formatter (Html). This formatter will be able to take stuff (like a String
, Unit
, Seq[Int]
, Map[A,B]
, ...) and render it into HTML code.
格式化将在使用 BaseScalaTemplate
的 _display_
方法时进行,该方法返回 格式化输出 的一个实例.此显示方法将在对象的apply
方法主体中的.scala.html
文件的编译 代码中调用.
Formatting will take place while using the _display_
method of BaseScalaTemplate
, which returns an instance of the formatted output. This display method will be called in the compiled code of the .scala.html
file in the object's apply
method's body.
所以身体可以这样结束:
So the body could end like that:
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_
调用不会改变任何东西,但它们的组合方式是 apply 本身将返回格式化代码的实例 (Html
)!
See? The _display_
calls aren't mutating anything but they are composed in such a way that apply itself will return an instance of the formatted code (Html
)!
这给了我们线索......
That gives us the clue...
是的,等等……现在为什么?
在关于 Play 内部结构的那些闪电之后,我们现在可以解决真正的问题:为什么问题帖子中提供的意识形态 Scala 代码不起作用......阅读,根本不输出任何内容.
After those lightnings given about the Play internals, we can now tackle the real question: why the hell is the ideomatic Scala code provided in the question post isn't working... read, doesn't output anything at all.
这非常简单,当在 Map
上使用 foreach
时,您确实循环在项目上并适应em> 将它们转换为 Html.但是这些计算不会被模板系统使用,因为它们被包含在 foreach
的循环中.也就是说,当序列中的每个项目都需要副作用时,必须使用 foreach
...并在完成后返回 Unit
.
It's pretty simple, when using foreach
on a Map
, you're indeed looping over the items and adapting them to Html. But these computation won't be usable by the templating system because they are enclosed in the foreach
's loop. That is foreach
has to be used when side-effects are required for each item in the sequence... And return Unit
when it's done.
因为,模板系统会尝试在给定的 Map
上 _display_
foreach
的结果,它只会渲染/格式化 单位
,因此是一个空的String
!
Since, the templating system will try to _display_
the result of foreach
on the given Map
it will simply render/format Unit
and thus an empty String
!
总而言之,只需使用 map
它将返回一个包含 适应 项的新序列,即 Html
实例.
To conclude, just use map
which will return a new sequence holding the adapted items, the Html
instance.
嗯,for
怎么样?
Hmmm and what about the for
?
是的,你说得对...根据已经说过的,为什么建议使用 for
循环的答案有效,因为没有产生值,for
等价于 foreach
!?(引入 yield
会以类似 map
的行为结束)
Yeah, you're right... Based on what has been said, why are the answers that proposed to used a for
loop working, since without yielding a value, a for
is equivalent to foreach
!? (Introducing yield
will end in a map
-like behavior)
答案在代码中...模板编译器会将 yield
关键字添加到 for
的正文中 -- 请查看 这里一>.:-D
The answer is in the code... The Template compiler will prepend the yield
keyword to the for
's body -- check this out here. :-D
等一下,它也可以工作,因为 for
主体中生成的内容将在完成后附加到返回的序列中.
Et voilà, it works too, since the generated stuffs in the for
's body will be attached to a returned sequence after it has finished.
这篇关于玩!Framework 2.0 - 在 Scala 模板中循环遍历地图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!