Выражения и операторы
Выражение — все, что вычисляется в значение: member.rank.level + 1, chat.memberCount >= 1000, member.username ?: 'нет'. Выражения пишутся внутри и в тегах.
Арифметика
| Оператор | Что делает | Пример | Результат |
|---|---|---|---|
+ | Сложение | 2 + 3 | 5 |
- | Вычитание | 10 - 4 | 6 |
* | Умножение | 2.5 * 2 | 5 |
/ | Деление с дробной частью | 7 / 2 | 3.5 |
// | Деление с округлением до целого (0,5 — от нуля) | 5 // 2 | 3 |
% | Остаток от деления (со знаком делимого) | 7 % 3 | 1 |
^ | Степень | 2 ^ 3 | 8 |
** | Умножение с отбрасыванием дробной части | 2.2 ** 2.2 | 4 |
Оба операнда приводятся к числу: '12' + 3 дает 15. Если текст не число, результат пустой (Undefined), а в строгом режиме — ошибка type_error. Деление на ноль — ошибка division_by_zero.
** — это не степень
** — целочисленное умножение, а степень — ^.
Склейка строк
Оператор ~ превращает оба операнда в строки и склеивает их:
{% set text = 'Уровень ' ~ member.rank.level ~ '!' %}
{{ "5" ~ "2" }} {# 52, а не 7 #}Сравнения
| Оператор | Значит |
|---|---|
==, != | Равно, не равно |
<, <=, >, >= | Меньше, меньше или равно, больше, больше или равно |
in | Содержится ли: элемент в списке, ключ в карте, подстрока в строке |
Если оба значения можно превратить в числа, сравниваются числа, иначе — строки. Поэтому '10' == 10 — true, а null == 0 — тоже true: пустое значение приводится к нулю.
{{ 'Броулбол' in ['Броулбол', 'Нокаут'] }} {# true #}
{{ 'vip' in { vip: 500 } }} {# true #}
{{ 'клуб' in 'Мой клуб Astral' }} {# true #}Логика
| Оператор | Значит |
|---|---|
and | И: истинно, если истинны оба |
or | ИЛИ: истинно, если истинно хотя бы одно |
not | НЕ: меняет истину на ложь |
and и or вычисляются лениво: если результат ясен по левой части, правая не вычисляется. Результат всегда логический: true или false.
and и or — один приоритет
В этом языке and и or равноправны и выполняются слева направо: a or b and c — это (a or b) and c. В большинстве языков программирования иначе. Всегда ставьте скобки, если смешиваете их. Редактор предупредит об этом.
Pipe: передача в функцию
Вертикальная черта передает значение слева первым аргументом в функцию справа:
| Запись | То же самое |
|---|---|
x | abs | abs(x) |
name | upper | upper(name) |
list | join(', ') | join(list, ', ') |
tag | upper | replace('#', '') | replace(upper(tag), '#', '') |
Pipe работает и с макросами.
Pipe выполняется последним
У | очень низкий приоритет — ниже, чем у сравнений и арифметики. Запись members | length < 10 значит members | (length < 10), а не «длина меньше 10». Заключайте pipe в скобки: (members | length) < 10.
Значение по умолчанию: ?:
Оператор Элвис a ?: b возвращает a, если оно истинно, иначе b:
{{ member.username ?: 'без username' }}
{% set page = parameters.get('page') ?: 0 %}Тернарный оператор: ? :
условие ? если_да : если_нет:
{{ member.isPremium ? '⭐ Premium' : 'обычный аккаунт' }}
{{ r.type == 'project' ? 'проектный' : 'клубный' }}Присваивание с возвратом: :=
:= присваивает значение существующей переменной и сразу возвращает его — удобно внутри условия:
{% set coins = 0 %}
{% if (coins := member.getAttribute('coins').value) > 100 %}Богач: {{ coins }}{% endif %}:= не создает новую глобальную переменную, но обновляет уже существующую.
Тесты is
| Тест | Истинно, когда | Пример |
|---|---|---|
is null | Значение null | x is null |
is defined | Значение определено (не Undefined) | parameters.page is defined |
is empty | Пусто: null, Undefined, '', [], {}, 0 | arguments.get(1) is empty |
is number | Число или текст, который можно превратить в число | arguments.get(1) is number |
is even, is odd | Четное, нечетное | loop.index is even |
is iterable | Список, карта или страница индекса | x is iterable |
is divisible by (n) | Делится на n без остатка | 9 is divisible by (3) |
is same as (x) | Тот же самый объект | null is same as (null) |
Любой тест можно отрицать: is not.
У тестов самый низкий приоритет: a and b is null читается как (a and b) is null. Если сочетаете тест с and или or, берите тест в скобки: (x is null) or y.
{% require arguments.get(1) is number returning 'Нужно число' %}
{% if loop.index is divisible by (3) %}{% do row() %}{% endif %}Приоритет операторов
Чем меньше число, тем раньше выполняется операция. Операторы одного уровня выполняются слева направо.
| Приоритет | Конструкция | Пример |
|---|---|---|
| 1 | Переменная | member |
| 10 | Вызов функции или метода | round(x), member.getAttribute('k') |
| 20–80 | Литералы: карта, список, диапазон, строка, число, логическое, null | [1, 2] |
| 90 | Скобки | (a + b) |
| 95 | Унарный минус | -(-1) |
| 100 | not | not false |
| 101 | Доступ к свойству . и по индексу [ ] | member.id, list[0] |
| 103 | Степень ^ | 2 ^ 3 |
| 105 | *, **, /, //, % | |
| 110 | +, - | |
| 112 | Склейка ~ | 'a' ~ 'b' |
| 115 | <, <=, >, >=, in | |
| 120 | ==, != | |
| 125 | and, or | |
| 130 | Pipe | | -5 | abs |
| 140 | Присваивание := | (x := 5) > 0 |
| 160 | Элвис ?: | a ?: 'по умолчанию' |
| 170 | Тернарный ? : | a ? 1 : 2 |
| 180 | Тесты is, is not | x is null |
Скобки вокруг not и минуса
not и унарный минус стоят в таблице выше, чем точка. Чтобы не гадать, как прочитается not member.bot или -member.rank.level, пишите со скобками: not (member.bot), -(member.rank.level).
Запись list[0] + list[1]
Доступ по индексу стоит на одном уровне с точкой, поэтому такая запись разбирается и работает без скобок.