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

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

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

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

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

// Целочисленные типы
let возраст: int = 25
let большоеЧисло: bigint = 9999999999999999999

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

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

Булев тип

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

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

Символы и строки

// Символ (одиночный)
let оценка: char = 'A'
let эмодзи: char = '🎉'

// Строка
let имя = "Иван Топаз"
let длинноеПредложение = "Добро пожаловать в Топаз, язык, где код становится поэзией!"

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

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

Массивы

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

// Манипуляции с массивом
let первый = числа[0]           // 1
числа.push(6)                   // [1, 2, 3, 4, 5, 6]
let длина = числа.length()      // 6

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

Объекты

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

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

// Объект с методами
let калькулятор = {
    значение: 0,
    добавить: function(x: int) -> int {
        this.значение += x
        return this.значение
    },
    умножить: function(x: int) -> int {
        this.значение *= x
        return this.значение
    }
}

калькулятор.добавить(10).умножить(2)      // цепочка методов

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

Тип Option

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

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

// Безопасная обработка с ?. и ??
let длина = имяПользователя?.length ?? 0

Тип Result

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

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

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

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

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

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

🧬 Дженерик типы

Дженерик функции

// Дженерик функция с параметрами типа
function создатьМассив<T>(значение: T, количество: int) -> [T] {
    let результат: [T] = []
    for i in 0..количество {
        результат.push(значение)
    }
    return результат
}

let массивЧисел = создатьМассив(42, 5)      // [42, 42, 42, 42, 42]
let массивСтрок = создатьМассив("привет", 3) // ["привет", "привет", "привет"]

Дженерик структуры

// Определение дженерик структуры
struct Контейнер<T> {
    значение: T,
    
    function установитьЗначение(новоеЗначение: T) {
        this.значение = новоеЗначение
    }
    
    function получитьЗначение() -> T {
        return this.значение
    }
}

let числовойКонтейнер = Контейнер { значение: 100 }
let строковыйКонтейнер = Контейнер { значение: "Привет" }

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

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

type ФункцияОбратногоВызова = function(данные: string) -> void
type ОбновительСостояния<T> = function(предыдущееСостояние: T) -> T

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

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

// Явное преобразование типов
let строковоеЧисло = "123"
let число = int(строковоеЧисло)         // 123
let вещественное = float(число)         // 123.0
let обратноВСтроку = string(вещественное) // "123.0"

// Безопасное преобразование типов
let результат = tryInt("abc")             // Option<int>
match результат {
    case Some(значение) => print("Преобразование успешно: {значение}")
    case None => print("Преобразование не удалось")
}

// Проверка типа
let значение: any = "Привет"
if значение is string {
    print("Это строка: {значение as string}")
}

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

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

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

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

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

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

// Пользовательский защитник типа
function этоСтрока(значение: any): значение is string {
    match значение {
        case _: string => true
        case _ => false
    }
}

function безопаснаяОбработка(значение: any) {
    if этоСтрока(значение) {
        // значение здесь обрабатывается как тип string
        print(значение.toUpperCase())
    }
}

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

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

type Пользователь = {
    id: int,
    имя: string,
    почта: string,
    датаСоздания: Date
}

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

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