Axiom Справочник языка

12 · Составные значения

Кортежи и распаковка

Кортеж объединяет несколько значений разных типов и позволяет обращаться к нужной части по имени или позиции.

Объявление и начальные значения

Кортеж хранит несколько связанных значений под одним именем. Его компоненты имеют фиксированный порядок; каждый компонент обладает собственным типом. При объявлении имена и типы компонентов записываются в круглых скобках после AS:

DIM purchase AS (Cost AS INTEGER, Change AS INTEGER)

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

DIM purchase AS (Cost, Change AS INTEGER)

В одном кортеже могут быть компоненты разных типов. Группа имён заканчивается своей частью AS тип:

DIM result AS (Name AS STRING, Cost, Change AS INTEGER, Paid AS BOOLEAN)

В кортеже должно быть не менее двух компонентов. Имена задаются либо всем компонентам, либо ни одному. Имена не различают регистр и не должны повторяться или иметь вид Item1, Item2 и так далее: эти обозначения предназначены для доступа по позиции.

Без начального выражения компоненты получают обычные начальные значения своего типа: числа равны 0, строки пусты, BOOLEAN равен FALSE. Вложенные записи и коллекции получают свои обычные начальные значения.

DIM purchase AS (Cost, Change AS INTEGER)
PRINT purchase.Cost, purchase.Change

Вывод: 0 0.

Значение и доступ к компоненту

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

Начальное значение может находиться непосредственно в объявлении:

DIM purchase AS (Cost, Change AS INTEGER) = (60, 40)

Можно объявить переменную и присвоить ей значение позже:

DIM purchase AS (Cost, Change AS INTEGER)
purchase = (60, 40)

Отдельный компонент читается или изменяется через точку. Каждому компоненту соответствует также позиционное имя: Item1 обозначает первый, Item2 — второй и так далее.

purchase.Cost = 70
PRINT purchase.Item1, purchase.Change

Вывод: 70 40. Доступ по имени и по позиции обращается к одному компоненту.

Имена можно не задавать:

DIM pair AS (INTEGER, STRING) = (2, "яблоки")
PRINT pair.Item1, pair.Item2

Вывод: 2 яблоки. Если тип выводится из позиционного значения, компоненты также получают имена Item1, Item2:

DIM pair = (2, "яблоки")

Компонентами могут быть числа, строки, логические и временные значения, записи TYPE, массивы, DICTIONARY, HASHSET и другие кортежи. Непосредственные функции и внешние ресурсы в компоненте не допускаются; STRING * N как тип компонента не поддерживается. Массивы и поля TYPE сохраняют собственные правила объявления и доступа. Целый кортеж нельзя вывести через PRINT или вставить в интерполированную строку: выводятся его компоненты.

Результат функции и параметры

Функция может вернуть одним кортежем несколько результатов. Тип после последнего AS описывает возвращаемые части; RETURN передаёт их в том же порядке.

FUNCTION BuyApples(quantity, price, paid AS INTEGER) AS (Cost, Change AS INTEGER)
    DIM total AS INTEGER = quantity * price
    RETURN (total, paid - total)
END FUNCTION

DIM purchase = BuyApples(3, 20, 100)
PRINT purchase.Cost, purchase.Change

Вывод: 60 40. В объявлении purchase тип и имена компонентов определяются по результату функции. При необходимости тип можно указать явно:

DIM purchase AS (Cost AS INTEGER, Change AS INTEGER) = BuyApples(3, 20, 100)

Полная запись функции перечисляет тип каждого параметра и каждого компонента результата:

FUNCTION BuyApples(quantity AS INTEGER, price AS INTEGER, paid AS INTEGER) AS (Cost AS INTEGER, Change AS INTEGER)

Сокращённая запись той же сигнатуры:

FUNCTION BuyApples(quantity, price, paid AS INTEGER) AS (Cost, Change AS INTEGER)

В параметрах SUB также допускаются полная и сокращённая записи:

SUB Show(first AS INTEGER, second AS INTEGER)
SUB Show(first, second AS INTEGER)

Обе формы объявляют два параметра INTEGER. Явный BYREF или BYVAL перед первой переменной относится к группе: BYREF first, second AS INTEGER. Для другого режима сначала заканчивают текущую группу, например BYREF first AS INTEGER, BYVAL second AS INTEGER.

Распаковка

Распаковка помещает компоненты кортежа в отдельные переменные того же порядка. Объявление создаёт новые имена и определяет их типы по источнику:

DIM purchase AS (Cost, Change AS INTEGER) = (60, 40)
DIM (cost, change) = purchase
PRINT cost, change

Вывод: 60 40.

Присваивание использует уже объявленные изменяемые переменные:

(cost, change) = (change, cost)
PRINT cost, change

Вывод: 40 60. Источник вычисляется один раз; значения и необходимые преобразования подготавливаются до изменения любой из целевых переменных. Это позволяет обменять значения без дополнительной переменной. Каждая цель указывается один раз; число целей равно числу компонентов. Непосредственная распаковка во вложенный список, поле или индекс элемента не поддерживается.

Копирование, передача и сравнение

Присваивание, инициализация, возврат из функции и пользовательский параметр BYVAL создают независимое значение, включая вложенные массивы, записи, словари и множества. Изменение компонента копии не меняет исходный кортеж. Явный BYREF связывает параметр с переданной переменной; изменить эту переменную можно через её компоненты. Для непосредственного аргумента BYREF действуют обычные ограничения на адресуемую переменную.

DIM first AS (Cost, Change AS INTEGER) = (60, 40)
DIM second = first
second.Cost = 99
PRINT first.Cost, second.Cost

Вывод: 60 99.

Совместимость определяется числом, порядком и типами компонентов. Имена служат для доступа и не меняют совместимость. Для каждой позиции применяются разрешённые преобразования типа. Кортеж и именованный TYPE не являются взаимозаменяемыми. Кортежи одинакового структурного типа можно сравнивать операторами = и <>, если все компоненты поддерживают структурное равенство. Упорядоченное сравнение целого кортежа не предусмотрено.

Диагностика и примеры

MB2003 сообщает о несовпадении числа компонентов и значений, несовместимом типе, повторном имени компонента или цели распаковки, а также о недопустимом типе компонента. MB2023 сообщает о неизвестном имени компонента. MB2010 возникает при присваивании константе, включая цель распаковки. MB2022 сообщает о циклическом объявлении TYPE через кортеж, MB2026 — о недопустимой строке фиксированной длины в компоненте, MB2028 — о недопустимом аргументе BYREF.

При незавершённой или ошибочной записи разбор может сообщить MB1001, если отсутствует ожидаемый токен, MB1002 для недопустимого имени, MB1003 при отсутствии выражения или MB1004 при неожиданном токене.

Покупка и независимая копия · Распаковка и обмен · Вложенные товары · Ошибка числа значений.

DIM · Присваивание · Вызовы и параметры · TYPE