Играть!Framework 2.0 - цикл по карте в шаблоне Scala? - PullRequest
14 голосов
/ 30 марта 2012

У меня есть карта, представляющая оглавление, она содержит 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 ]

17 голосов
/ 31 марта 2012

Решение, которое я придумал, выглядело так. По сути, он просто избегает использования функционального программирования, с которым у меня пока все в порядке, но я все же очень хотел бы увидеть рабочее решение с использованием функционального стиля 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>
  }
}
17 голосов
/ 22 мая 2013

ТЛ; др

Ответы, данные до сих пор ( @ wbarksdale , @ PlexQ и @ Daniel C. Sobral в комментарии) достаточно хороши, чтобы нацелить проблему описано здесь.

Но им не хватает реального объяснения того, почему исходный код, использующий foreach, не работает.

Не может работать, потому что foreach возвращает Unit.

Концепции игры

Позвольте мне кратко заметить / вспомнить, как работают шаблоны.

Система шаблонов Scala, предоставляемая по умолчанию в Play Framework 2, действительно построена на концепциях 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 - проверьте это здесь . : -D

Et voilà , это тоже работает, так как сгенерированные элементы в теле for будут присоединены к возвращенной последовательности после ее завершения.

8 голосов
/ 30 марта 2012

Игра в Scala очень хорошо использует функциональную природу Scala. Измените это на карту, которая возвращает элементы, и она должна работать.

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

В соответствии с предложением выше, в данном случае он превращает его в частичную функцию, которая довольно хорошо выполняет то, что нам нужно!

...