Подтвердить что ты не робот

Играть! Framework 2.0 - Цитирование через карту в шаблоне 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) в начало шаблона, чтобы убедиться, что на карте действительно были данные и она напечатана:

{[email protected]=BeanList size[4] hasMoreRows[false] list[[email protected], [email protected], [email protected], [email protected]], [email protected]=BeanList size[0] hasMoreRows[false] list[]}

Возможно, мне нужно использовать императивный стиль?

UPDATE:

Все еще работая над этим... получил этот вариант для компиляции, но без вывода.

<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>
  }
}
4b9b3361

Ответ 1

TL;DR

Ответы, полученные до сих пор (@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, работали, так как без получения значения a for эквивалентно foreach!? (Представляя yield, закончится поведением Map)

Ответ в коде... Компилятор шаблона добавит ключевое слово yield к телу for - проверьте это здесь.:-D

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

Ответ 2

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

Ответ 3

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

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

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