Операторы

Изучите все операторы Топаза с полным руководством. Освойте использование и приоритет арифметических, логических, побитовых, сравнения, присваивания и специальных операторов.

Топаз предоставляет различные операторы для манипулирования и вычисления данных. Понимание точного поведения и приоритета всех операторов является критически важным. ⚡

🔢 Арифметические операторы

Базовые арифметические операции

// Основные арифметические операторы
let число1 = 10
let число2 = 3

let сложение = число1 + число2        // 13
let вычитание = число1 - число2       // 7  
let умножение = число1 * число2       // 30
let деление = число1 / число2         // 3.333...
let остаток = число1 % число2         // 1
let возведение = число1 ** число2     // 1000

print("Сложение: {сложение}")
print("Вычитание: {вычитание}")
print("Умножение: {умножение}")
print("Деление: {деление}")
print("Остаток: {остаток}")
print("Возведение в степень: {возведение}")

Унарные операторы

let положительное = +42     // 42 (явно положительное)
let отрицательное = -42     // -42 (отрицание)

let число = 15
let обращённое = -число     // -15

print("Исходное значение: {число}")
print("Обращённое: {обращённое}")

Операторы инкремента/декремента

let mut счётчик = 5

счётчик = счётчик + 1
счётчик = счётчик - 1

function увеличить(значение: int) -> int { значение + 1 }
function уменьшить(значение: int) -> int { значение - 1 }

счётчик = увеличить(счётчик)
счётчик = уменьшить(счётчик)

print("Итоговое значение счётчика: {счётчик}")

Составные операторы присваивания

let mut значение = 10

значение += 5     // значение = значение + 5 = 15
значение -= 3     // значение = значение - 3 = 12  
значение *= 2     // значение = значение * 2 = 24
значение /= 4     // значение = значение / 4 = 6
значение %= 4     // значение = значение % 4 = 2
значение **= 3    // значение = значение ** 3 = 8

print("Итоговое значение: {значение}")

🔍 Операторы сравнения

Базовые сравнения

let икс = 10
let игрек = 20
let зет = 10

// Сравнение на равенство
let равно = икс == зет         // true
let неРавно = икс != игрек     // true

// Сравнение размера
let меньше = икс < игрек              // true
let меньшеИлиРавно = икс <= зет       // true
let больше = игрек > икс              // true
let большеИлиРавно = зет >= икс       // true

print("икс == зет: {равно}")
print("икс != игрек: {неРавно}")
print("икс < игрек: {меньше}")
print("игрек > икс: {больше}")

Типобезопасное сравнение

// Топаз обеспечивает типобезопасное сравнение
let целое = 42
let вещественное = 42.0
let строка = "42"

// Только одинаковые типы можно сравнивать
let сравнениеЦелых = целое == 42              // true
let сравнениеВещественных = вещественное == 42.0    // true

// Сравнение разных типов требует явного преобразования
let сравнениеСтрок = целое.toString() == строка        // true
let сравнениеЧисел = целое == parseInt(строка)         // true

print("Сравнение с преобразованием типа: {сравнениеСтрок}")

Специальные операторы сравнения

Топаз v4 не включает оператор <=> (spaceship).

🧠 Логические операторы

Базовые логические операции

let истина = true
let ложь = false

// Логическое И
let результатИ = истина && ложь      // false
let результатИ2 = истина && истина   // true

// Логическое ИЛИ  
let результатИли = истина || ложь       // true
let результатИли2 = ложь || ложь        // false

// Логическое НЕ
let результатНе = !истина            // false
let результатНе2 = !ложь             // true

print("Результат И: {результатИ}")
print("Результат ИЛИ: {результатИли}")
print("Результат НЕ: {результатНе}")

Короткое замыкание

function функцияСПобочнымЭффектом() -> bool {
    print("Функция была вызвана!")
    return true
}

// Короткое замыкание И - второе не выполняется, если первое false
let короткоеИ = false && функцияСПобочнымЭффектом()  // Функция не вызвана

// Короткое замыкание ИЛИ - второе не выполняется, если первое true
let короткоеИли = true || функцияСПобочнымЭффектом()   // Функция не вызвана

print("Короткое И: {короткоеИ}")
print("Короткое ИЛИ: {короткоеИли}")

Оператор объединения с null

// Оператор объединения с null (??)
let значение1: Option<string> = None
let значение2: Option<string> = Some("по умолчанию")
let значение3 = "резервное"

let результат1 = значение1 ?? "ничего"           // "ничего"
let результат2 = значение2 ?? "ничего"           // "по умолчанию"  
let результат3 = значение1 ?? значение2 ?? значение3 // "по умолчанию"

print("Результат объединения с null: {результат1}")

// С Option
let пользователь = { имя: "РазработчикТопаз", возраст: Some(25) }
let возраст = match пользователь.возраст { case Some(v) => v; case None => 0 }
print("Возраст: {возраст}")

Присваивание объединения с null (??=)

Оператор присваивания, который инициализирует переменную только если она сейчас None/null. Это оператор‑оператор на уровне оператора (statement‑only): не возвращает значение выражения. Правоассоциативный.

let mut name: Option<string> = None
name ??= Some("guest")     // name станет Some("guest")
name ??= Some("override")  // без изменений (уже Some)

// Правоассоциативность
a ??= b ??= Some(1)   // то же, что: a ??= (b ??= Some(1))

🔧 Побитовые/сдвиговые операторы

В Топазе v4 побитовые и сдвиговые операторы отсутствуют. Обратите внимание, что >> зарезервирован под композицию функций (а не битовый сдвиг). См. раздел о композиции ниже.

🎯 Специальные операторы

Операторы типов

В Топазе v4 отсутствуют typeof и instanceof. Для определения типа используйте сопоставление образцов или утилиты стандартной библиотеки.

Операторы диапазона

// Диапазоны: .. (включительно), ..< (верхняя граница исключена)
let включительно = 1..5       // 1, 2, 3, 4, 5
let исключаяВерхнюю = 1..<5   // 1, 2, 3, 4

for x in включительно { print(x) }
for x in исключаяВерхнюю { print(x) }

Оператор принадлежности (in)

// Массивы/Списки/Множества
let ok1 = 3 in [1, 2, 3]                      // true
let ok2 = "a" in Set.of("a", "b")            // true

// Ключи map (через представление keys)
let hasId = "id" in userMap.keys               // bool

// Диапазоны
let inside = 5 in 1..10                         // true
let outside = 10 in 1..<10                      // false

Оператор распространения

В синтаксис Топаза v4 не входит.

Опциональная цепочка (?.)

Только для Option/nullable. Парсится, когда слева Option<T> или объединение с null (например, T | null). Это не общий объектный чейнинг; для обычного доступа используйте ..

let user: Option<{ name: string, profile: Option<{ city: string }> }> =
    Some({ name: "Ann", profile: Some({ city: "Seoul" }) })

let nameOpt = user?.name              // Option<string>
let cityOpt = user?.profile?.city     // Option<string>
let city    = user?.profile?.city ?? "Unknown"  // string

let noneUser: Option<{ name: string }> = None
let fallback = noneUser?.name ?? "guest"       // "guest"

// Сводится к цепочке Option.map/flatMap

Оператор конвейера

// Оператор конвейера (|>)
let результат = 10
    |> (х => х * 2)        // 20
    |> (х => х + 5)        // 25
    |> (х => х.toString())  // "25"

// Полезно для цепочки функций
let данные = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    |> (масс => масс.filter=> х % 2 == 0))  // [2, 4, 6, 8, 10]
    |> (масс => масс.map=> х * х))           // [4, 16, 36, 64, 100]
    |> (масс => масс.reduce((а, б) => а + б))  // 220

print("Результат конвейера: {результат}")
print("Результат цепочки: {данные}")

⚡ Приоритет операторов (Топаз v4)

v4
// Высокий → Низкий; ассоциативность указана
1) Вызов/Индекс/Доступ: () [] . ?. (левый)
2) Возведение в степень: ** (правый)
3) Унарные: + - ! (правый)
4) Умножение/Деление/Остаток: * / % (левый)
5) Сложение/Вычитание: + - (левый)
6) Диапазон: .. ..< (левый)  // ниже арифметики, выше сравнений
7) Сравнения: < <= > >= == != in (левый)
8) Логическое И: && (левый)
9) Логическое ИЛИ: || (левый)
10) Объединение с null: ?? (левый)
11) Композиция функций: >> (правый)
12) Конвейер: |> (левый)
13) Присваивание: = …, ??= (правый)

// >> выше |> (|> ниже >>)
let h = f >> g
let x = вход |> h          // т.е. вход |> (f >> g)

Композиция функций (>>)

let нормализация = trim >> toLowerCase >> collapseSpaces
print(нормализация("  Hello   WORLD  "))  // "hello world"

🔄 Перегрузка операторов

Операторы для пользовательских типов

// Реализация операторов для структур
struct Вектор {
    x: float,
    y: float
}

impl Вектор {
    // Перегрузка оператора +
    function +(другой: Вектор) -> Вектор {
        return Вектор { x: self.x + другой.x, y: self.y + другой.y }
    }
    
    // Перегрузка оператора * (скалярное умножение)
    function *(скаляр: float) -> Вектор {
        return Вектор { x: self.x * скаляр, y: self.y * скаляр }
    }
    
    // Перегрузка оператора ==
    function ==(другой: Вектор) -> bool {
        return self.x == другой.x && self.y == другой.y
    }
    
    // Преобразование в строку
    function toString() -> string {
        return "Вектор({self.x}, {self.y})"
    }
}

// Примеры использования
let вектор1 = Вектор { x: 3.0, y: 4.0 }
let вектор2 = Вектор { x: 1.0, y: 2.0 }

let сумма = вектор1 + вектор2             // Вектор(4.0, 6.0)
let масштабированный = вектор1 * 2.0      // Вектор(6.0, 8.0)
let равны = вектор1 == вектор2            // false

print("Сумма векторов: {сумма}")
print("Масштабированный вектор: {масштабированный}")
print("Векторы равны: {равны}")

🛡️ Безопасное использование операторов

1. Обработка переполнения

// Проверяемые арифметические операции
let большоеЧисло1 = 2147483647  // максимальное значение int
let большоеЧисло2 = 1

// Безопасное сложение (проверка переполнения)
match большоеЧисло1.checkedAdd(большоеЧисло2) {
    case Some(результат) => print("Безопасное сложение: {результат}")
    case None => print("Произошло переполнение!")
}

// Насыщающие операции (ограничение до макс/мин значений)
let насыщающееСложение = большоеЧисло1.saturatingAdd(большоеЧисло2)  // остаётся на макс int
print("Насыщающее сложение: {насыщающееСложение}")

2. Предотвращение деления на ноль

function безопасноеДеление(числитель: float, знаменатель: float) -> Result<float, string> {
    if знаменатель == 0.0 {
        return Err("Нельзя делить на ноль")
    }
    return Ok(числитель / знаменатель)
}

// Пример использования
match безопасноеДеление(10.0, 0.0) {
    case Ok(результат) => print("Результат деления: {результат}")
    case Err(ошибка) => print("Ошибка: {ошибка}")
}

3. Типобезопасность

// Обеспечение безопасности явным преобразованием типов
let строковоеЧисло = "123"
let настоящееЧисло = match parseInt(строковоеЧисло) {
    case Ok(число) => число
    case Err(_) => {
        print("Преобразование числа не удалось")
        0  // значение по умолчанию
    }
}

let результат = настоящееЧисло + 100
print("Результат безопасного вычисления: {результат}")

📊 Советы по оптимизации производительности

1. Оптимизация дорогих операций

// Используйте умножение вместо возведения в степень (для малых степеней)
let квадрат = значение * значение           // вместо значение ** 2
let куб = значение * значение * значение    // вместо значение ** 3

// Используйте умножение вместо деления
let половина = значение * 0.5          // вместо значение / 2

// Оптимизируйте операции остатка (степени 2)
let остаток = значение & 7          // вместо значение % 8 (8 = 2^3)

2. Используйте короткое замыкание

// Размещайте дорогие вызовы функций позже
let результат = простоеУсловие() && дорогаяФункция()

// Оптимизируйте проверки на null
let значение = объект?.свойство?.подСвойство ?? значениеПоУмолчанию

Понимание и правильное использование операторов Топазе позволяет вам писать эффективный и безопасный код! Всегда помните о приоритете операторов и типобезопасности. 🎯