玩! Framework 2.0 - 通过scala模板中的地图循环?

时间:2012-03-30 16:04:14

标签: templates scala playframework playframework-2.0

我有一张代表目录的地图,它包含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>
  }
}

3 个答案:

答案 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)构建的。此格式化程序将能够获取内容(例如StringUnitSeq[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>

根据上面的建议,在这种情况下,它将它变成一个部分功能,可以很好地完成我们想要的功能!