1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
## Линейные типы
Большинство типов в YQL являются неизменяемыми, то есть выражения возвращают новые значения, а не меняют существующие.
Этот подход, принятый в функциональных языках программирования, позволяет проводить более агрессивные оптимизации (например, удалять общие подвыражения или кешировать результаты).
Но в некоторых сценариях это может приводить к более медленному выполнению запроса, в частности при попытке изменить одно значение в списке/словаре необходимо или возвращать полную копию, или использовать персистентные структуры данных, что также имеет дополнительные накладные расходы.
Линейные типы предлагают другой подход — вместо того, чтобы переиспользовать неизменяемые результаты вычисления выражения, повторное использование значения линейного типа запрещено. Оно передается как бы по эстафете от точки создания до точки поглощения, где оно преобразуется уже в обычное неизменяемое значение.
Линейные типы доступны начиная с версии [2025.04](../changelog/2025.04.md).
Линейные типы описываются одним параметром-типом T и бывают двух видов — статически верифицируемые `Linear<T>` и верифицируемые во время выполнения `DynamicLinear<T>`.
Статически верифицируемые типы более эффективные, но имеют ограничения по композиции.
Обычно в параметре `T` линейного типа используется тип `Resource`. В этом случае пользовательские функции (UDF) могут передавать такие данные друг другу с гарантией защиты от повторного использования в запросе, что позволяет использовать более эффективную реализацию.
Линейные типы не являются сериализуемыми — их нельзя прочитать/записать в таблицы, т.е. их можно использовать только в середине выражений.
Функции, принимающие или возвращающие линейные типы, делятся на 3 класса:
* Если линейный тип содержится в результате, но не в аргументах - это порождающая функция;
* Если линейный тип содержится и в аргументах и в результате - это трансформирующая функция;
* Если линейный тип содержится в аргументах, но не в результате - это поглощающая функция.
Порождающая функция обязательно принимает зависимое выражение как минимум в одном аргументе, так как можно построить из входных аргументов несколько независимых значений линейных типов.
Создавать и поглощать линейные типы рекомендуется внутри функции [`Block`](../builtins/basic.md#block), позволяющей ввести анонимное зависимое выражение как аргумент `lambda`.
### Правила проверки статических линейных типов `Linear<T>`
* `Linear` типы проверяются как последняя стадия оптимизации, и, если оптимизатор устранил повторное использование выражения, то ошибки не возникает.
* `Linear` тип не может быть аргументом `lambda`.
* `Linear` тип не может возвращаться из `lambda`.
* `Linear` тип можно использовать либо сам по себе, либо как поле в `Struct/Tuple` (без вложенности). При этом по возможности отслеживается индивидуальное использование полей `Struct/Tuple` через оператор обращения к полю (точка).
При необходимости использования значений линейных типов внутри других контейнерных типов (например, в списках) следует использовать `DynamicLinear` тип.
### Правила проверки динамических линейных типов `DynamicLinear<T>`
* Функция `FromDynamicLinear` или пользовательские функции (UDF) могут извлечь значение такого типа, но не более одного раза - иначе возникнет ошибка выполнения запроса.
|