Шпаргалка по конвейерам и функциям в html/template (Go)

Конвейеры позволяют последовательно применять функции к данным в шаблонах.

Синтаксис:

{{value | function1 | function2 | ...}}

Примеры:

<!-- Простой конвейер -->
<p>{{.Name | upper}}</p>

<!-- Множественные функции -->
<p>{{.Title | trim | lower | trunc 50}}</p>

<!-- С аргументами -->
<p>{{.Date | format "2006-01-02"}}</p>

<!-- Вложенные конвейеры -->
<p>{{.Description | trunc 100 | html}}</p>

Встроенные функции

1. Строковые функции

{{"hello" | title}}      <!-- Hello -->
{{"HELLO" | lower}}      <!-- hello -->
{{"hello" | upper}}      <!-- HELLO -->
{{"  hello  " | trim}}   <!-- hello -->
{{"hello" | repeat 3}}   <!-- hellohellohello -->

2. HTML-функции

{{"<script>" | html}}         <!-- Экранирование HTML -->
{{"<b>safe</b>" | html}}      <!-- &lt;b&gt;safe&lt;/b&gt; -->
{{"<b>safe</b>" | safeHTML}}  <!-- <b>safe</b> (без экранирования) -->

3. Функции для коллекций

{{len .Items}}               <!-- Длина массива/слайса/мапы -->
{{index .Users 0}}           <!-- Первый элемент -->
{{index .Map "key"}}         <!-- Значение по ключу -->
{{slice .List 1 3}}          <!-- Подслайс -->

4. Логические функции

{{if eq .A .B}}...{{end}}     <!-- Равно -->
{{if ne .A .B}}...{{end}}     <!-- Не равно -->
{{if lt .A .B}}...{{end}}     <!-- Меньше -->
{{if le .A .B}}...{{end}}     <!-- Меньше или равно -->
{{if gt .A .B}}...{{end}}     <!-- Больше -->
{{if ge .A .B}}...{{end}}     <!-- Больше или равно -->

{{if and .A .B}}...{{end}}    <!-- Логическое И -->
{{if or .A .B}}...{{end}}     <!-- Логическое ИЛИ -->
{{if not .A}}...{{end}}       <!-- Логическое НЕ -->

5. Математические функции

{{add 1 2}}        <!-- 3 -->
{{sub 5 2}}        <!-- 3 -->
{{mul 3 4}}        <!-- 12 -->
{{div 10 2}}       <!-- 5 -->
{{mod 10 3}}       <!-- 1 -->

6. Функции форматирования

{{printf "%s - %d" .Name .Age}}  <!-- Форматированная строка -->
{{.Price | printf "$%.2f"}}      <!-- Форматирование числа -->
{{.Date | date "2006-01-02"}}    <!-- Форматирование даты -->

Пользовательские функции

Регистрация функций:

funcMap := template.FuncMap{
    "upper":    strings.ToUpper,
    "trunc":    func(s string, max int) string {
        if len(s) > max {
            return s[:max] + "..."
        }
        return s
    },
    "add":      func(a, b int) int { return a + b },
    "contains": strings.Contains,
    "now":      time.Now,
}

tmpl := template.New("").Funcs(funcMap)

Использование в шаблоне:

{{.Title | trunc 50 | upper}}
{{add .Value 10}}
{{if contains .Description "important"}}Important!{{end}}
{{now | date "2006-01-02"}}

Примеры сложных конвейеров

1. Обработка текста

{{.UserComment | trim | trunc 200 | html}}

2. Форматирование данных

{{.CreatedAt | date "02.01.2006" | printf "Created: %s"}}

3. Работа с коллекциями

{{range .Items | sortBy "Name" | limit 10}}
    {{.Name | upper}}
{{end}}

4. Условные конвейеры

{{if .Price | gt 100}}
    <p class="expensive">{{.Price | printf "$%.2f"}}</p>
{{else}}
    <p>{{.Price | printf "$%.2f"}}</p>
{{end}}

Полезные комбинации

Безопасный вывод HTML:

{{.UserContent | sanitizeHTML | safeHTML}}

Форматирование денежных значений:

{{.Amount | div 100 | printf "$%.2f"}}

Сортировка и фильтрация:

{{range .Products | filter "category" "electronics" | sortBy "price"}}
    {{.Name}} - {{.Price | printf "$%.2f"}}
{{end}}

Ограничения

  1. Функции должны возвращать только одно значение (и опционально ошибку)
  2. Невозможно передавать функции как аргументы
  3. Нет поддержки сложных операций с каналами
  4. Автоматическое экранирование применяется к конечному результату

Лучшие практики

  1. Выносите сложную логику в Go-код, а не в шаблоны
  2. Используйте конвейеры для читаемости, но не переусердствуйте
  3. Документируйте пользовательские функции
  4. Тестируйте шаблоны с разными входными данными
  5. Избегайте побочных эффектов в функциях