---
url: https://docs.juniper.bot/message-templates/advanced/expressions.md
description: Описание операторов и выражений шаблонного движка JuniperBot.
---

# Операторы и выражения { #expressions }

Выражением называется совокупность переменных, констант, знаков операций, имен функций, скобок, которая может быть вычислена.
Результатом вычисления выражения является величина определенного [типа данных](../types/index).

## Идентификаторы { #identifiers }

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

### Ключевые слова { #keywords }

В шаблонном движке есть набор зарезервированных ключевых слов для построения сложных конструкций, они могут
использоваться в [тэгах](tags) и других выражениях. Несмотря на то, что они являются корректными идентификаторами, их
использование в качестве идентификаторов недопустимо.

Ниже перечислены все зарезервированные ключевые слова:

| `set`     | `in`        |
|-----------|-------------|
| `global`  | `as`        |
| `if`      | `do`        |
| `elseif`  | `verbatim`  |
| `else`    | `filter`    |
| `endif`   | `endfilter` |
| `for`     | `null`      |
| `endfor`  | `is`        |
| `true`    | `not`       |
| `false`   | `with`      |
| `empty`   | `require`   |
| `return`  | `returning` |
| `include` | `macro`     |

## Выражения доступа { #access-expressions }

### Значения списков и карт { #value-access }

Для получения доступа к элементу [списка](../types/index#lists) или значению ключа [карты](../types/index#maps)
используется индекс элемента списка или название ключа карты, заключенные в квадратные скобки `[]`.
Индексы списков всегда начинаются с 0.

```template
{{ list[0] }}
{{ map["key1"] }}
```

::: warning
Выражения получения доступа к элементам списка или значению ключа карты в комбинации с [бинарными операторами](#binary) очень чувствительны к скобкам.

Это техническое ограничение архитектуры парсера шаблонного движка, о котором можно ознакомиться подробнее [здесь](precedence#limitations).
:::

### Свойства и методы { #properties-access }

Для получения доступа к свойству какого-либо объекта или вызова метода этого объекта, используется оператор выбора `.` (точка).
Допустимые свойства и методы описаны в разделах [Переменные](variables) и [Типы данных](../types/index).

```template
{{ guild.name }}
{{ guild.getMember(247734710682255361) }}
```

Оператор выбора может также использоваться в [картах](../types/index#maps) для получения доступа к значению, используя
название ключа как название свойства, если оно является корректным [идентификатором](#identifiers):

```template
{{ map.key1 }}
```

## Сложные выражения { #complex-expressions }

Константы, переменные и другие выражения могут объединяться в более сложные выражения с помощью операторов.

Операторы шаблонного движка делятся на несколько групп:

1. [Унарные операторы](#unary);
2. [Бинарные операторы](#binary);
3. [Тернарный оператор](#ternary);
4. [Оператор Элвиса](#elvis).

### Порядок вычисления { #precedence }

В выражениях с множеством операторов, операторы с более высоким приоритетом вычисляются раньше выражений с более низким
приоритетом. Операторы одинакового приоритета вычисляются в лексическом порядке.

Для изменения порядка вычисления, заданного приоритетом операторов, можно использовать скобки.

Более подробно о приоритетах выражений читайте в статье [Приоритет выражений](precedence).

::: tip
Чем меньше число, тем выше приоритет оператора, тем раньше он вычисляется.
:::

### Унарные операторы { #unary }

Унарные операторы по определению нуждаются только в одном аргументе, шаблонизатор JuniperBot содержит только два встроенных унарных оператора: `not` и `-`.

| Символ | Описание    | Приоритет | Пример                                                     |
|--------|-------------|-----------|------------------------------------------------------------|
| `-`    | Меняет знак | 95        | `-(-1)` выводит `1`                                        |
| `not`  | Отрицание   | 100       | `not false` выводит `true`  `not true` выводит `false` |

### Бинарные операторы { #binary }

Шаблонный движок JuniperBot поддерживает следующие бинарные операторы:

::: tip
Чем меньше число, тем выше приоритет оператора, тем раньше он вычисляется.
:::

| Символ              | Приоритет | Описание                                                                                                                   | Пример                                                                     |
|:--------------------|:----------|:---------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------|
| `.`                 | 101       | Получение доступа к свойствам объектов                                                                                     | `member.id` выводит идентификатор участника                                |
| `^`                 | 103       | Возводит число в степень                                                                                                   | `2 ^ 3` выводит `8`                                                        |
| `*`                 | 105       | Умножение двух значений                                                                                                    | `2.2 * 2.2` выводит `4.84`                                                 |
| `**`                | 105       | Целочисленное умножение двух значений                                                                                      | `2.2 ** 2.2` выводит `4`                                                   |
| `/`                 | 105       | Деление двух значений                                                                                                      | `5.0 / 2.0` выводит `2.5`                                                  |
| `//`                | 105       | Деление двух значений с округлением до целого                                                                              | `5.0 // 2.0` выводит `3`                                                   |
| `%`                 | 105       | Получение остатка от деления                                                                                               | `5 % 2` выводит `1`                                                        |
| `+`                 | 110       | Суммирует два значения                                                                                                     | `5 + 2` выводит `7`                                                        |
| `-`                 | 110       | Вычитает два значения                                                                                                      | `5 - 2` выводит `3`                                                        |
| `~`                 | 112       | Объединяет две строки                                                                                                      | `"5" ~ "2"` выводит `"52"`                                                 |
| `<`                 | 115       | Сравнивает два значения, проверяя меньше ли первое значение второе                                                         | `1 < 2` выводит `true` `1 < 1` выводит `false`                             |
| `<=`                | 115       | Сравнивает два значения, проверяя меньше или равно ли первое значение второму                                              | `2 <= 2` выводит `true` `2 < 1` выводит `false`                            |
| `>`                 | 115       | Сравнивает два значения, проверяя больше ли первое значение второго                                                        | `2 > 1` выводит `true` `2 > 2` выводит `false`                             |
| `>=`                | 115       | Сравнивает два значения, проверяя больше или равно ли первое значение второму                                              | `2 >= 2` выводит `true` `2 >= 3` выводит `false`                           |
| `in`                | 115       | Проверяет, содержится ли значение в списке                                                                                 | `5 in [2]` выводит `false`                                                 |
| `==`                | 120       | Проверяет два значения на их равенство                                                                                     | `true == false` выводит `false` `false == false` выводит `true`            |
| `!=`                | 120       | Проверяет два значения на их неравенство                                                                                   | `true != false` выводит `true` `false != false` выводит `false`            |
| `and`               | 125       | Оператор конъюнкции (И)                                                                                                    | `true and false` выводит `false` `true and true` выводит `true`            |
| `or`                | 125       | Оператор дизъюнкции (ИЛИ)                                                                                                  | `true or false` выводит `true` `false or false` выводит `false`            |
| | | 130       | Использует первый аргумент как параметр к названию функции во втором аргументе                                             | -5 | abs выводит `5`                                     |
| `:=`                | 140       | Вычисляет и возвращает значение второго аргумента, присваивая его переменной в первом аргументе. [Подробнее](#assignment). | `result := 1 + 2` выводит `3`, присвоя это же значение переменной `result` |

#### Оператор присваивания { #assignment }

Оператор присваивания (так называемый моржовый оператор `:=`) относится к группе бинарных операторов и позволяет
одновременно присвоить значение переменной и вернуть его.

```template
{{ <переменная> := <выражение> }}
```

Моржик вычисляет значение выражения, записывает его в переменную и возвращает это же значение.

```template
{{ result := 1 + 2 }}
{{ result }}
```

Пример выше распечатает "3" два раза. Первая тройка - результат вычисления выражения присваивания, а вторая - значение
переменной `result` в результате вычисления этого выражения.

Этот оператор очень полезен для сокращения кода в некоторых ситуациях. Например, представим простой шаблон с
использованием обычного [тэга set](tags#set) для присваивания переменной:

```template
{% set amount = 5 %}
{% if amount > 0 %}
У Пети есть целых {{ amount }} яблок!
{% endif %}
```

Этот шаблон можно сократить таким образом:

```template
{% if (amount := 5) > 0 %}
У Пети есть целых {{ amount }} яблок!
{% endif %}
```

::: info Приоритет присваивания
Как вы можете видеть в таблице выше, среди бинарных операторов у оператора присваивания самый низкий приоритет и это следует учитывать.

Если выражение сравнения в примере выше было бы записано как `amount := 5 > 0`, то значение переменной `amount` было бы
не `5`, а `true`, поскольку согласно приоритетам оператор сравнения вычисляется в первую очередь.
Именно поэтому для изолирования выражения присваивания используются скобки.
:::

Сам по себе оператор присваивания не может объявлять [глобальные](tags#global) переменные, но если переменная с
указанным названием уже существует и она является глобальной, то оператор присваивания обновит значение этой переменной,
оставив её при этом глобальной.

### Тернарный оператор { #ternary }

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

```template
{{ <выражение> ? 1 : 2 }}
```

Такой блок выведет `1`, если результат вычисления `выражения` равен `true` и `2`, если `false`.

### Оператор Элвиса { #elvis }

Оператор Элвиса возвращает результат вычисления первого выражения в случае, если оно имеет значение истины согласно
[Конвертации типов](../types/type-convert#boolean), в противном случае возвращает результат вычисления второго выражения.

```template
{{ <выражение A> ?: <выражение Б> }}
```

Этот оператор очень полезен для определения значений по умолчанию во втором выражении, когда значение первого выражения отсутствует.

::: tip
По своей природе оператор Элвиса должен являться бинарным, но с точки зрения правил шаблонного движка он вынесен в
отдельную группу, приоритет которой ещё ниже, чем вся группа бинарных выражений, но выше тернарного оператора.
:::

## Тестовые выражения { #test }

Тестовые выражения представляют собой сложные предикатные конструкции, в результате вычисления которых возвращается логическое значение.

| Название                 | Описание                                                             | Пример                                                                |
|--------------------------|----------------------------------------------------------------------|-----------------------------------------------------------------------|
| Null                     | Проверяет, является ли значение                                      | `1 is null` выводит `false`                                           |
| Divisible                | Проверяет, можно ли поделить первое значение на второе               | `2 is divisible by 1` выводит `true`                                  |
| [Same As](#test-same-as) | Проверяет, являются ли два объекта одним и тем же объектом по ссылке | `1 is same as (2)` выводит `false`                                    |
| Function based           | Проверяет результат вычисления функции над указанным аргументом.     | `4 is defined` выводит `true`;`'test' is number` выводит `false`. |
| Is Not                   | В любых конструкциях выше можно использовать отрицание `is not`.     | `4 is not defined` выводит `false`                                    |

#### Тестовое выражение "Same As" { #test-same-as }

Данное выражение проверяет равность объектов по их ссылке, а не просто по значению. Например:

```template
{{ 1 is same as (1) }}
```

Данный пример распечатает `false`. Да, это два одинаковых числа `1`, но это разные экземпляры этого числа, имеющие
разные ссылки. Теперь взгляните на этот шаблон:

```template
{% set value = 1 %}
{% set other = value %}
{{ value is same as (other) }}
```

Этот шаблон распечатает `true`, потому что обе переменные `value` и `other` ссылаются на один и тот же экземпляр числа.

Однако это работает для `null`:

```template
{{ null is same as (null) }}
```

Этот шаблон распечатает `true`, потому что нулевая ссылка всегда одна и та же.
