Переменные и область видимости

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

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

🔧 Объявление переменных

let - Неизменяемые переменные (по умолчанию)

// Все переменные по умолчанию неизменяемы
let имя = "Иван Топаз"
let возраст = 25
let активен = true

// Нельзя изменить после определения
// имя = "Другое имя"  // Ошибка компиляции!

let mut - Изменяемые переменные

// Используйте let mut, когда нужно изменять значения
let mut счёт = 100
let mut сообщение = "Начальное сообщение"

// Значение можно изменить
счёт = 95
сообщение = "Обновлённое сообщение"

print("Текущий счёт: {счёт}")  // "Текущий счёт: 95"

const - Константы времени компиляции

// Константы, определяемые во время компиляции
const MAX_SIZE: int = 1000
const APP_NAME: string = "Топаз Calculator"
const PI: float = 3.141592653589793

// Глобальные константы, доступные в других файлах
const настройкиПоУмолчанию = {
    язык: "Русский",
    тема: "тёмная",
    автосохранение: true
}

🎯 Вывод типов и явные типы

// Вывод типов (рекомендуется)
let выведенноеЧисло = 42           // int
let выведеннаяСтрока = "Привет"    // string
let выведенныйМассив = [1, 2, 3]   // [int]

// Явные типы (когда необходимо)
let явноеЧисло: int = 42
let явнаяСтрока: string = "Привет"
let явныйМассив: [int] = [1, 2, 3]

// Явные типы помогают в сложных случаях
let данныеПользователя: { имя: string, возраст: int } = {
    имя: "Разработчик Иванов",
    возраст: 30
}

🏠 Правила области видимости

Глобальная область видимости

// Верхний уровень файла - глобальная область видимости
let глобальнаяПеременная = "Доступна везде"
const глобальнаяКонстанта = 100

function использоватьВезде() {
    print(глобальнаяПеременная)  // Доступна
    print(глобальнаяКонстанта)   // Доступна
}

Область видимости функции

function калькулятор(a: int, b: int) -> int {
    // Параметры функции также принадлежат области видимости функции
    let результат = a + b        // Область видимости функции
    let mut временноеЗначение = a * 2 // Область видимости функции
    
    print("Результат: {результат}")
    return результат
}

// print(результат)  // Ошибка! Нельзя получить доступ вне функции

Блочная область видимости

function примерОбластиВидимости() {
    let внешняяПеременная = "снаружи"
    
    if true {
        let внутренняяПеременная = "внутри"      // Блочная область видимости
        let mut блочнаяИзменяемая = 10               // Блочная область видимости
        
        print(внешняяПеременная)                 // Доступна (внешняя область)
        print(внутренняяПеременная)              // Доступна (та же область)
    }
    
    print(внешняяПеременная)                     // Доступна
    // print(внутренняяПеременная)               // Ошибка! Нельзя получить доступ вне блока
}

Область видимости цикла

// Переменные цикла for имеют область видимости цикла
for i in 0..5 {
    let переменнаяЦикла = i * 2
    print("i: {i}, значение: {переменнаяЦикла}")
}

// print(i)  // Ошибка! Нельзя получить доступ вне цикла

// Циклы while работают аналогично
let mut счётчик = 0
while счётчик < 3 {
    let временная = счётчик + 10
    print(временная)
    счётчик += 1
}

🔒 Затенение переменных

let имя = "Иван Топаз"

function примерЗатенения() {
    let имя = "Разработчик Петров"        // Затеняет глобальное имя
    print("В функции: {имя}")             // "В функции: Разработчик Петров"
    
    {
        let имя = "Дизайнер Сидоров"       // Затеняет имя функции
        print("В блоке: {имя}")            // "В блоке: Дизайнер Сидоров"
    }
    
    print("После блока: {имя}")           // "После блока: Разработчик Петров"
}

print("Глобальное: {имя}")               // "Глобальное: Иван Топаз"
примерЗатенения()

🌟 Замыкания и область видимости

function создатьСчётчик(начальноеЗначение: int) -> function() -> int {
    let mut счёт = начальноеЗначение           // Захватывается замыканием
    
    return function() -> int {
        счёт += 1                          // Доступ к переменной внешней области
        return счёт
    }
}

let счётчик1 = создатьСчётчик(0)
let счётчик2 = создатьСчётчик(100)

print(счётчик1())  // 1
print(счётчик1())  // 2
print(счётчик2())  // 101
print(счётчик1())  // 3

🎭 Сопоставление образцов и переменные

let пользователь = {
    имя: "Иван Топаз",
    возраст: 28,
    работа: "Разработчик"
}

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

// Привязка переменных в match
match пользователь.возраст {
    case возраст if возраст < 20 => print("Вероятно, студент")
    case возраст if возраст < 30 => print("Молодой специалист")
    case возраст => print("Опытный: {возраст} лет")
}

// Сопоставление образцов массива
let оценки = [95, 87, 92, 88]
match оценки {
    case [первая, вторая, ...остальные] => {
        print("Первая: {первая}")
        print("Вторая: {вторая}")
        print("Остальные: {остальные}")
    }
}

⚡ Продвинутые паттерны области видимости

НВФВ (Немедленно вызываемое функциональное выражение)

// Немедленно вызываемая функция для изоляции области видимости
let результат = (function() -> int {
    let временныйРасчёт = 10 * 20
    let корректировка = 50
    return временныйРасчёт + корректировка
})()

print(результат)  // 250
// временныйРасчёт, корректировка недоступны

Область видимости модуля

// файл math_utils.tpz
export const PI = 3.141592653589793
export let точностьПоУмолчанию = 6

export function площадьКруга(радиус: float) -> float {
    let внутреннийРасчёт = радиус * радиус    // Доступен только в модуле
    return PI * внутреннийРасчёт
}

// файл main.tpz
import { PI, площадьКруга } from "./math_utils"

print(PI)                    // Доступно
print(площадьКруга(5.0))     // Доступно
// print(внутреннийРасчёт)   // Ошибка! Внутренняя переменная модуля недоступна

🛡️ Лучшие практики

1. Используйте неизменяемость по умолчанию

// Хорошо: используйте let по умолчанию
let конфигурация = {
    тема: "тёмная",
    язык: "Русский"
}

// Используйте let mut только при необходимости
let mut статусПрогресса = "начато"
статусПрогресса = "в процессе"
статусПрогресса = "завершено"

2. Осмысленные имена переменных

// Плохой пример
let a = списокПользователей.length()
let b = a * 0.1

// Хороший пример  
let общееКоличествоПользователей = списокПользователей.length()
let комиссия = общееКоличествоПользователей * 0.1

3. Минимизируйте область видимости

function обработатьДанные(исходныеДанные: [int]) -> [int] {
    let результат = []
    
    for элемент in исходныеДанные {
        // Переменные, нужные только в цикле, должны объявляться в цикле
        let преобразованноеЗначение = элемент * 2 + 1
        let проверенноеЗначение = if преобразованноеЗначение > 0 { преобразованноеЗначение } else { 0 }
        
        результат.push(проверенноеЗначение)
    }
    
    return результат
}

🔍 Советы по отладке

// Утилита для отладки области видимости
function выводИнформацииООбласти() {
    let локальнаяПеременная = "локальная"
    
    print("Переменные в текущей функции:")
    print("- локальнаяПеременная: {локальнаяПеременная}")
    
    // Доступ к глобальным переменным
    if defined(глобальнаяПеременная) {
        print("- Глобальная переменная доступна")
    }
}

// Проверка существования переменной
function безопасныйДоступ(имяПеременной: string) {
    if defined(имяПеременной) {
        print("{имяПеременной} определена")
    } else {
        print("{имяПеременной} не определена")
    }
}

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