Основы языка

Типы

Разберитесь с выводом и аннотациями типов, а затем выбирайте объединения, типы функций и номинальные данные по смыслу границы.

Эта страница описывает Топаз v5.17. Прежде чем считать её актуальной, сверьте поле version в /version.json со значением 5.17.

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

Начните с одной проверяемой программы

Сохраните этот код в файле types.tpz:

TOPAZ
type Стадия = "draft" | "ready"

function описать(стадия: Стадия, проверки: int) -> string {
    "{стадия} after {проверки} checks"
}

let проверки = 3
let текущая: Стадия = "ready"
let показать: (Стадия, int) -> string = описать

print(показать(текущая, проверки))

Сначала проверьте границы типов, затем запустите программу:

BASH
topaz check types.tpz
topaz run types.tpz

Результат:

Вывод
ready after 3 checks

Прочитайте типы по коду и результату

У проверки нет аннотации. Начальное значение — целое число, поэтому Топаз выводит тип int. У текущая аннотация есть: программе требуется именно Стадия, а не любая строка string.

Стадия — прозрачный псевдоним для объединения литералов "draft" | "ready". Такое объединение разрешает одно из двух перечисленных значений и отклоняет любую другую строку. Псевдоним даёт выбору понятное имя, но не создаёт отдельной сущности во время выполнения.

У показать указан тип функции. Запись (Стадия, int) -> string означает «функция принимает Стадия и int, а возвращает string». Именованная функция описать имеет именно такую форму, поэтому её можно сохранить в привязке и вызвать позднее.

Названия базовых типов пишутся строчными буквами: int, float, bool, string и единичный тип (). Для контейнеров используются именованные конструкторы Array<T>, Map<K, V> и Set<T>. Ожидаемое отсутствие значения выражается через Option<T>, а восстанавливаемая ошибка — через Result<T, E>.

Выберите форму, которая передаёт намерение

ЗадачаЧто выбратьПочему
Очевидное локальное значениеВывод типаНачальное значение уже ясно показывает тип.
Публичный вход, результат или важная локальная границаАннотациюПроверяющий и читатель сразу видят задуманный контракт.
Одно значение из закрытого набора вариантовОбъединение или псевдоним объединения литераловВсе допустимые варианты перечислены явно.
Значение, которое позже будут вызыватьТип функции, например (int) -> boolТипы параметров и результата хранятся вместе с функцией.
Самостоятельная сущность предметной области, поля или именованные вариантыrecord, enum или newtypeНоминальные объявления остаются разными, даже если устроены похоже.

Псевдоним type делает код понятнее, но остаётся прозрачным. Если смешение двух похожих по форме значений было бы настоящей ошибкой, выбирайте номинальные данные. На странице Записи и номинальные данные сопоставлены создание и сопоставление для record, enum и newtype.

Дайте пустому значению контекст

Некоторые значения сами по себе не сообщают достаточно сведений. Пустой массив не показывает тип элемента, а None — тип отсутствующего значения. Контекст можно задать аннотацией, параметром функции, объявленным результатом или окружающим типом:

let имена: Array<string> = []
let выбранное: Option<int> = None

Здесь канонические формы показаны как текст. Проверяемой программой этой страницы остаётся полный пример выше.

Частая ошибка: перенос записи типов из целевого языка

Типы коллекций Топаза записываются как Array<T>, Map<K, V> и Set<T>. В типе функции параметры заключаются в круглые скобки, после чего -> отделяет тип результата. Единая запись помогает проверяющему и создаваемым целевым программам опираться на один исходный контракт.

Точные ограничения

  • Между int и float нет неявного преобразования.
  • Параметры обобщённых типов инвариантны: разные аргументы типов не становятся совместимыми лишь из-за сходства содержимого.
  • Ограничения обобщённого типа допускаются только у параметров именованной функции. Разрешённая форма первого ранга описана на странице Функции и обобщения.
  • Рекурсивные псевдонимы, аннотации вариантности, полиморфизм высших рангов и более широкая рефлексия пока отложены.
  • Если контекст так и не определил параметры пустого обобщённого значения, это статическая ошибка, а не повод угадывать тип во время выполнения.

Если вывод типов, аннотации и изменяемость ещё непривычны, вернитесь к уроку Значения и функции. Выбор между отсутствием, восстанавливаемой ошибкой и сбоем разобран на странице Null, Option, Result и ошибки.