播放/ Scala模板块语句包含局部变量的

时间:2015-08-18 19:56:24

标签: scala playframework playframework-2.0

好的,我已经花了一段时间来处理这个问题,并花了很多时间尝试不同的事情来做一些我用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模板语法正在加剧这种知识。我不知道该怎么做。

提前致谢!

1 个答案:

答案 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
  }
}){
  ...
}