Данные и управление

Записи и номинальные данные

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

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

Установите Топаз по уроку Первая программа. Если вы впервые работаете с записями, начните с урока Данные и управление.

Создайте и обновите пользователя

Сохраните код в файле records-nominal-data.tpz в своей рабочей папке.

TOPAZ
type ОтображаемоеЗначение = int | string

newtype ИдентификаторПользователя = int

enum Состояние {
    Активен,
    Приостановлен(string),
}

record Пользователь {
    идентификатор: ИдентификаторПользователя,
    имя: string,
    состояние: Состояние = Состояние.Активен,
}

function меткаСостояния(состояние: Состояние) -> string {
    match состояние {
        case Активен => "active"
        case Приостановлен(причина) => причина
    }
}

function показать(значение: ОтображаемоеЗначение) -> string {
    match значение {
        case число: int => "number {число}"
        case текст: string => текст
    }
}

let до: Пользователь = Пользователь {
    идентификатор: ИдентификаторПользователя(7),
    имя: "Ada",
}
let после: Пользователь = Пользователь {
    ...до,
    состояние: Состояние.Приостановлен("review"),
}
let сводка = { имя: "Ada", возраст: 36 }
let старше = сводка{ возраст: 37 }
let готово = показать("ready")

print("{до.идентификатор.value()}:{до.имя}:{меткаСостояния(до.состояние)}")
print("{после.имя}:{меткаСостояния(после.состояние)}")
print("{сводка.возраст}:{старше.возраст}")
print("{показать(7)}:{готово}")

В этой же папке проверьте файл и запустите его.

BASH
topaz check records-nominal-data.tpz
topaz run records-nominal-data.tpz

Проверка завершается с кодом 0. Программа печатает следующий результат.

Вывод
7:Ada:active
Ada:review
36:37
number 7:ready

Прочитайте результат

Запись до получает состояние Активен по умолчанию. Запись после сохраняет идентификатор и имя, но получает состояние Приостановлен("review"). Обновление сохраняет исходную запись и не вычисляет значения по умолчанию повторно.

сводка объединяет два поля без именованного объявления записи. Обновление возраста создаёт запись старше, поэтому третья строка содержит 36:37.

ОтображаемоеЗначение служит псевдонимом объединения. Оно принимает int или string без дополнительной оболочки. Шаблоны типов в функции показать выбирают подходящий тип и связывают значение с именем.

Различайте поля и объявления

Совместимость структурной записи определяется именами и типами полей. Например, сводка имеет структуру { имя: string, возраст: int }.

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

Объявление newtype ИдентификаторПользователя = int создаёт отдельный тип вокруг целого числа. Создайте значение через ИдентификаторПользователя(7) и прочитайте число методом .value(). Каждый вызов снимает один слой.

Что нужноЧто выбратьПример
Значение, определяемое набором полейСтруктурная записьсводка
Отдельный тип с именованными полямиНоминальная recordПользователь
Один из объявленных вариантовenumСостояние.Активен или Состояние.Приостановлен(причина)
Значение одного из существующих типовОбъединение A | BОтображаемоеЗначение
Отдельный тип вокруг одного базового значенияnewtypeИдентификаторПользователя

Набор вариантов перечисления задан в его объявлении. Создавайте вариант через Состояние.Приостановлен("review"), а сопоставляйте через case Приостановлен(причина). Проверяющая программа требует обработать все варианты перечисления. Дополнительное условие ветви называют guard. Ветви с таким условием не учитываются при проверке полноты.

Создавайте и обновляйте поля

Топаз проверяет имена и типы полей. Явно заданные поля вычисляются слева направо. Затем значения по умолчанию для пропущенных полей вычисляются один раз в порядке объявления.

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

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

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

Ошибка во входной записиОшибка выполнения
Пропущенное или повторяющееся полеGUARD_ARITY (TPZ5004)
Неизвестное полеGUARD_NO_FIELD (TPZ5006)

Сопоставляйте записи и исправляйте ошибки

Шаблон case Пользователь { имя } => проверяет объявление и читает имя. Неуказанные поля игнорируются. Укажите хотя бы одно поле и используйте имя записи без пространства имён.

В примере обновляйте структурную запись через сводка{ возраст: 37 }, а именованную через Пользователь { ...до, состояние: Состояние.Приостановлен("review") }. Форма JavaScript { ...сводка } в Топазе недопустима.

Поместите методы в отдельный блок impl Пользователь на уровне модуля. Его self неизменяем и передаётся по значению. Тело записи не предоставляет неявные this, &self или &mut self.

Другие правила данных

  • Объявляйте записи, перечисления и новые типы на уровне модуля.
  • Обобщённые номинальные типы инвариантны, поэтому изменение аргумента типа даёт другой тип. Нужный при создании ожидаемый тип описан в разделе Типы.
  • Равенство, упорядочение и использование в качестве ключа коллекции учитывают объявление и содержимое. Вложенные типы тоже должны поддерживать операцию.
  • Рефлексия, наследование и типы записей с неопределённым набором дополнительных полей не поддерживаются. Номинальные шаблоны используют объявленные поля.
  • Создание записей и новых типов через пространство имён, выбор реализации протокола во время выполнения и получатели в стиле владения Rust не поддерживаются.

Продолжите в разделе Шаблоны и управление потоком, чтобы выбирать ветви и извлекать значения.