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 при неожиданном токене.
Покупка и независимая копия · Распаковка и обмен · Вложенные товары · Ошибка числа значений.