我有一张代表目录的地图,它包含Chapter
个密钥和List[Section]
个值。现在我试图在我的模板中循环这样:
<dl>
@table_of_contents.foreach((e) => {
<dt>
@e._1.title
</dt>
for(section <- e._2){
<dd>
@section.title
</dd>
}
})
</dl>
我目前在<dl>
中没有输出。
我在模板顶部添加了println(table_of_contents)
语句,以确保地图确实包含数据并打印出来:
{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[]}
也许我需要使用命令式的风格?
更新:
还在努力......得到这个变化来编译,但没有输出。
<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>
}
}
答案 0 :(得分:17)
我提出的解决方案看起来像这样。基本上它只是避免使用我目前正常使用的函数式编程,但我仍然希望看到一个使用scala函数式的工作解决方案。
<dl>
@for((key, value) <- table_of_contents) {
<dt>
@key.getTitle
</dt>
@displaySections(value)
}
</dl>
@displaySections(sections: List[Section]) = {
@for(a_section <- sections) {
<dd>@a_section.getTitle</li>
}
}
答案 1 :(得分:17)
<强> TL;博士强>
到目前为止给出的答案(在评论中@wbarksdale,@PlexQ和@Daniel C. Sobral)足以定位此处描述的问题。
但他们错过了一个真正的解释,说明为什么使用foreach
的初始代码不起作用。
它无效,因为foreach
会返回Unit
。
播放概念
让我快速记下/回顾一下模板是如何工作的。
Play Framework 2中默认提供的Scala模板系统确实是基于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
的正文中 - 请查看here。 :-D
Etvoilà,它也有效,因为for
主体中生成的东西将在完成后附加到返回的序列中。
答案 2 :(得分:8)
Scala中的游戏非常好地使用了Scala的功能特性。将其更改为返回元素的地图,它应该可以正常工作。
<dl>
@table_of_contents.map( case(k,v) => {
<dt>
@k.title
</dt>
@v.map { section =>
<dd>
@section.title
</dd>
}
})
</dl>
根据上面的建议,在这种情况下,它将它变成一个部分功能,可以很好地完成我们想要的功能!