Topazdocs
Основные концепции

Типы данных Топаз

Освойте систему типов Топаза: примитивы, коллекции, записи, опционалы и литеральные типы — как зафиксировано в спецификации v5.2.

Примечание о библиотечных именах: вспомогательные функции и вызовы методов вне минимума стандартной библиотеки (файлСуществует, прочитатьСодержимоеФайла, fetch, .ok, .json, .status, toUpperCase, Date и т.д.) являются иллюстративными заполнителями, а не каноническими API.

Топаз сочетает статическую систему типов с выводом типов. Код остаётся безопасным и при этом кратким. Компилятор автоматически выводит типы, когда вы их не указываете, но при необходимости можно быть явным.

Примитивные типы

Целые числа и вещественные

TOPAZ
// Целое число
let возраст: int = 25
let большойСчётчик: int = 9999999999

// Число с плавающей точкой
let цена: float = 19.99
let пи: float = 3.141592653589793

// Вывод типов
let счёт = 95        // выводится как int
let среднее = 87.5   // выводится как float

Примитивы Topaz: int (64-битное знаковое), float (IEEE-754 binary64), string, bool и (). При этом () также является выражением: единственным значением юнит-типа. Целые числа произвольной точности не специфицированы в Topaz v5.2, а int/float никогда не смешиваются неявно в арифметике.

Булев тип

TOPAZ
let активен = true
let естьПраваАдмина = false

// Использование в условиях
if активен {
    print("Сервис активен")
}

Строки

TOPAZ
// Строка (один символ или более длинный текст)
let оценка: string = "A"
let эмодзи: string = "😀"
let имя = "Иван Топаз"
let длинноеПредложение = "Добро пожаловать в Топаз — один способ сказать!"

// Интерполяция строк
let приветствие = "Привет, {имя}! Хорошая сегодня погода."
print(приветствие)  // "Привет, Иван Топаз! Хорошая сегодня погода."

Строки в одинарных кавычках и символьные литералы ('A', '') не являются каноническим синтаксисом Topaz. Используйте строки в двойных кавычках и для одного символа, и для более длинного текста. Строки не индексируются и не предоставляют .length. Доступ на уровне скаляров идёт через s.scalars().

Типы коллекций

Массивы

TOPAZ
// Объявление и инициализация массива
let mut числа: Array<int> = [1, 2, 3, 4, 5]
let имена = ["Алиса", "Боб", "Чарли"]  // выводится как Array<string>

// Манипуляции с массивом
let первый = числа[0]           // 1 — прямая индексация даёт фолт вне границ
let безопасно = числа.get(0)    // Some(1) — чтение без фолта, возвращает Option<int>
числа.push(6)                   // [1, 2, 3, 4, 5, 6]
let длина = числа.length        // 6

// Операции в функциональном стиле
let квадраты = map(числа, x => x * x)
let чётные = filter(числа, x => x % 2 == 0)

Записи

TOPAZ
// Определение записи
let пользователь = {
    имя: "Иван Топаз",
    возраст: 28,
    почта: "ivan@example.com",
    активен: true
}

// Доступ к свойствам
print(пользователь.имя)               // "Иван Топаз"

// Неизменяемое обновление через record literal
let калькулятор = { значение: 0 }
let послеСложения = калькулятор{ значение: калькулятор.значение + 10 }
let послеУмножения = послеСложения{ значение: послеСложения.значение * 2 }

print("{послеУмножения.значение}")        // 20
print("{калькулятор.значение}")           // 0 (исходное значение не меняется)

// Переиспользуемое поведение можно оформить обычными функциями
function добавитьККалькулятору(состояние: { значение: int }, x: int) -> { значение: int } {
    состояние{ значение: состояние.значение + x }
}

function умножитьКалькулятор(состояние: { значение: int }, x: int) -> { значение: int } {
    состояние{ значение: состояние.значение * x }
}

Продвинутые типы

Тип Option

TOPAZ
// Тип Option для безопасности от null
let результатПоиска: Option<string> = None
let имяПользователя: Option<string> = Some("admin")

// Безопасная обработка с сопоставлением образцов
match имяПользователя {
    case Some(имя) => print("Добро пожаловать, {имя}!")
    case None => print("Требуется авторизация")
}

// Безопасная обработка с ?. и ?? (строки не предоставляют .length;
// число скаляров считается через s.scalars())
let длинаИмени = имяПользователя?.scalars()?.length ?? 0
let отображение = имяПользователя ?? "guest"

Тип Result

TOPAZ
// Тип Result для обработки ошибок
function прочитатьФайл(путь: string) -> Result<string, string> {
    if файлСуществует(путь) {
        Ok(прочитатьСодержимоеФайла(путь))
    } else {
        Err("Файл не найден")
    }
}

// Безопасная обработка ошибок
match прочитатьФайл("data.txt") {
    case Ok(содержимое) => print("Содержимое файла: {содержимое}")
    case Err(сообщениеОшибки) => print("Произошла ошибка: {сообщениеОшибки}")
}

Объединённые типы (Union Types)

TOPAZ
// Тип, который может быть одним из нескольких типов
type ID = int | string
type Статус = "ожидание" | "обработка" | "завершено" | "ошибка"

let идПользователя: ID = 12345
let статусЗадачи: Статус = "обработка"

// Обработка для конкретного типа с сопоставлением образцов
function показатьID(id: ID) -> string {
    match id {
        case числовой: int => "Числовой ID: {числовой}"
        case текстовый: string => "Строковый ID: {текстовый}"
    }
}

Использование дженерик типов

TOPAZ
let числа: Array<int> = [1, 2, 3]
let имяОпционально: Option<string> = Some("Alice")
let результатПарсинга: Result<Пользователь, string> = разобратьПользователя(rawJson)
let кеш: Map<string, int> = Map.new()

Дженерик-функции и псевдонимы

Topaz поддерживает дженерик-объявления функций ранга 1 и дженерик-псевдонимы типов. Параметры типов выводятся в каждой точке вызова; явные аргументы типов вроде f<int>(x) не входят в Topaz v5.2. Фиксируйте тип аннотированной привязкой, параметром или позицией возврата.

TOPAZ
function первыйЭлемент<T>(xs: Array<T>) -> Option<T> {
    match xs {
        case [] => None
        case [первый, ..] => Some(первый)
    }
}

let первый: Option<int> = первыйЭлемент([1, 2, 3])

type Пара<T> = { первый: T, второй: T }
let границы: Пара<int> = { первый: 0, второй: 100 }

Границы дженериков, ограничения и интерфейсы остаются отложенными.

Псевдонимы типов

TOPAZ
// Даём простые имена сложным типам
type ИнфоПользователя = {
    имя: string,
    возраст: int,
    почта: string,
    разрешения: Array<string>
}

type ФункцияОбратногоВызова = (string) -> ()

// Пример использования
let администратор: ИнфоПользователя = {
    имя: "Админ Пользователь",
    возраст: 35,
    почта: "admin@topaz.ooo",
    разрешения: ["чтение", "запись", "удаление"]
}

Преобразование типов

TOPAZ
let строковоеЧисло = "123"

// toInt возвращает Option<int> — обрабатывайте случай None явно
let разобрано = match toInt(строковоеЧисло) {
    case Some(значение) => значение
    case None => 0
}

Стандартная библиотека Topaz определяет toInt(text: string) -> Option<int> как canonical helper для преобразования; он никогда не падает молча. Другие формы преобразования из legacy-примеров (float(...), string(...), tryInt(...)) являются иллюстративными placeholder, а не каноническими API.

Продвинутые паттерны

Деструктурирующее присваивание

TOPAZ
// Деструктурирование массива
let [первый, второй, ..остальные] = [1, 2, 3, 4, 5]
print("{первый}")       // 1
print("{остальные}")    // [3, 4, 5]

// Деструктурирование объекта
let { имя, возраст } = пользователь
print("Имя: {имя}, Возраст: {возраст}")

// Деструктурирование внутри тела функции
function поприветствовать(пользователь: { имя: string, возраст: int }) {
    let { имя, возраст } = пользователь
    print("Привет, {имя}! Вам {возраст} лет.")
}

Защитники типов

Topaz сужает типы через match + TypePattern, а не через is/as/any. Тип any и операторы is/as не являются каноническим синтаксисом Topaz. Примеры narrowing через match будут на странице управления потоком.

Практическое применение

TOPAZ
// Практические определения типов для реальных проектов
type Пользователь = {
    id: int,
    имя: string,
    почта: string,
    датаСоздания: string
}

type ОтветПользователя = {
    успех: bool,
    данные: Option<Пользователь>,
    ошибка: Option<string>,
    кодСостояния: int
}

// API получения пользователя
function получитьПользователя(id: int) -> ОтветПользователя {
    let ответ = fetch("/api/users/{id}")
    
    if ответ.ok {
        let данныеПользователя = ответ.json()
        return {
            успех: true,
            данные: Some(данныеПользователя),
            ошибка: None,
            кодСостояния: ответ.status
        }
    } else {
        return {
            успех: false,
            данные: None,
            ошибка: Some("Пользователь не найден"),
            кодСостояния: ответ.status
        }
    }
}

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