好的,我已经花了一段时间来处理这个问题,并花了很多时间尝试不同的事情来做一些我用PHP很容易做到的事情。
我正在尝试迭代列表,同时在本地跟踪变量,同时吐出HTML以尝试填充表。
尝试#1:
@{
var curDate : Date = null
for(ind <- indicators){
if(curDate == null || !curDate.equals(ind.getFirstFound())){
curDate = ind.getFirstFound()
<tr><th colspan='5' class='day'>@(ind.getFirstFound())</th></tr>
<tr><th>Document ID</th><th>Value</th><th>Owner</th><th>Document Title / Comment</th></tr>
}
}
}
我尝试使用scala块语句来允许我将curDate保持为创建范围内的变量。此块正确维护curDate状态,但不允许我向DOM输出任何内容。我实际上并没有期望这个编译,因为我的unescaped,随机抛出HTML,但确实如此。虽然决策结构在服务器上正确执行,但这个循环根本不会在DOM上放置任何内容。
我尝试使用@Html('...')
转义,但这会产生编译错误。
尝试#2:
很多谷歌搜索引导我进入&#34;理解&#34;:
@for(ind <- indicators; curDate = ind.getFirstFound()){
@if(curDate == null || !curDate.equals(ind.getFirstFound())){
@(curDate = ind.getFirstFound())
}
<tr><th colspan='5' class='day'>@(ind.getFirstFound())</th></tr>
<tr><th>Document ID</th><th>Value</th><th>Owner</th><th>Document Title / Comment</th></tr>
}
如果没有这个块中的if语句,这是我最接近我真正想做的事情,但显然我不允许重新分配非引用类型,这就是为什么我希望尝试#1&#39; curDate : Date = null
的参考声明可行。这个尝试让我获得页面上的HTML(再次,如果我删除嵌套的if语句)但是没有得到我的
我的问题是,我该如何实现这个意图?我非常痛苦地意识到我缺乏Scala知识,Play模板语法正在加剧这种知识。我不知道该怎么做。
提前致谢!
答案 0 :(得分:1)
Play的模板语言非常适合函数式编程。有可能使用可变状态实现您想要实现的目标,但您可能最好使用流程,并使用功能性解决方案。
如果你想在函数式编程中维持循环迭代之间的状态,可以通过折叠来完成 - 你从一些状态开始,并且在每次迭代时,你得到前一个状态和下一个元素,然后你然后根据这两件事返回新状态。
所以,看看你的第一个解决方案,看起来你要做的只是打印一个元素,如果它的日期与前一个不同,那是正确的吗?另一种方法是你要过滤掉所有日期与前一日期相同的元素。表示在折叠方面,我们将元素折叠成一个序列(我们的初始状态),如果折叠序列的最后一个元素与当前元素的日期不同,我们添加它,否则我们忽略它
我们的折叠看起来像这样:
indicators.foldLeft(Vector.empty[Indicator]) { (collected, next) =>
if (collected.lastOption.forall(_.getFirstFound != next.getFirstFound)) {
collected :+ next
} else {
collected
}
}
为了解释上述问题,我们将折叠成Vector
,因为Vector
有一个恒定的时间附加,最后,List
有n次。如果forall
中没有最后一个元素,collected
将返回true,否则,如果传入的lambda求值为true,则返回true。在Scala中,==
调用.equals
(在进行空检查后),因此您不需要在Scala中使用.equals
。
所以,把它放在一个模板中:
@for(ind <- indicators.foldLeft(Vector.empty[Indicator]) { (collected, next) =>
if (collected.lastOption.forall(_.getFirstFound != next.getFirstFound)) {
collected :+ next
} else {
collected
}
}){
...
}