在scala模板中循环浏览地图?

我有一张表示内容表的地图,它包含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>
  }
}

TL;博士

迄今为止给出的答案(@wbarksdale,@PlexQ和@Daniel C. Sobral在评论中)足以说明这里描述的问题。

但他们错过了关于为什么使用foreach的初始代码不起作用的真实解释。

它不能工作,因为foreach返回Unit

玩概念

让我快速记下/回忆一下模板如何工作。

Play Framework 2默认提供的Scala模板系统确实是建立在FP概念上的,因此它使用了很多不可变的结构等等。

此外,这样的Scala模板(比如myTemplate.scala.html )将被编译成一个常规的Scala object ,该object具有一个名为apply方法。 后一个函数使我们可以将该对象作为一个函数调用(在模板的第一行中声明的那些参数)。

这个object也依赖于像使用输出格式化程序(Html)构建的BaseScalaTemplate这样的构造。 这个格式化程序将能够获取东西(比如StringUnitSeq[Int]Map[A,B] ,...)并将其呈现为HTML代码。

而使用格式化将于_display_的方法BaseScalaTemplate ,它返回格式化输出的一个实例。 该显示方法将在对象的apply方法体内的.scala.html文件的编译代码中.scala.html

所以身体可以像这样结束:

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代码不工作...阅读,根本不输出任何内容。

这非常简单,当在Map上使用foreach时,你确实在遍历项目并将它们调整为Html。 但是这些计算不会被模板系统使用,因为它们被包含在foreach的循环中。 当序列中的每个项目都需要副作用时,必须使用foreach ...并在完成时返回Unit

因为,模板系统将尝试_display_结果foreach给定的Map它只会呈现/格式的Unit ,因此一个空String

总之,只需使用map将返回一个新的序列,其中包含适应的项目, Html实例。

嗯,什么对for

是啊,你说得对...基于说了些什么,为什么是建议使用的答案for循环工作,因为没有产生一个值, for相当于foreach !? (引入yield将以类似map的行为结束)

答案在代码中...模板编译器会将yield关键字添加到for的主体 - 请在此查看。 :-D

等瞧,它的工作原理也是如此,因为在生成的东西for ,它已经完成后的遗体将被连接到一个返回序列。


我提出的解决方案看起来像这样。 基本上,它只是避免使用函数式编程,我暂时可以使用,但我仍然很希望看到使用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>
  }
}

在斯卡拉玩Scala非常好用。 将其更改为返回元素的映射,它应该可以工作。

<dl>
@table_of_contents.map( case(k,v) => {
    <dt>
        @k.title
    </dt>
    @v.map { section =>
        <dd>
            @section.title
        </dd>
    }
})
</dl>

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

链接地址: http://www.djcxy.com/p/62631.html

上一篇: Looping through a map in a scala template?

下一篇: Why does pattern matching in Scala not work with variables?