Понимание замыканий

Откройте силу замыканий в Топазе. Полное руководство от базовых концептов до продвинутых паттернов и практических применений.

Замыкания — одна из основных концепций и самых элегантных особенностей функционального программирования. Испытайте магию замыканий в Топазе! ✨

🌱 Основные концепции замыканий

Что такое замыкания?

Замыкание — это функция, которая может запоминать и обращаться к переменным из окружения, где она была определена. Это называется замыканием, потому что функция "замыкается" над окружением (областью видимости) из момента своего создания.

// Базовый пример замыкания
function внешняяФункция(внешняяПеременная: int) -> impl Fn(int) -> int {
    // Создание замыкания - захватывает внешнююПеременную
    let внутренняяФункция = |внутренняяПеременная: int| -> int {
        внешняяПеременная + внутренняяПеременная  // Обращение к переменной из внешней области
    }
    
    return внутренняяФункция
}

// Пример счётчика с замыканием
function создатьСчётчик(начальноеЗначение: int) -> impl Fn() -> int {
    let mut текущееЗначение = начальноеЗначение
    
    // Замыкание, захватывающее текущееЗначение
    return move || -> int {
        текущееЗначение += 1
        текущееЗначение
    }
}

// Генератор функций умножения
function создатьУмножитель(множитель: int) -> impl Fn(int) -> int {
    |значение: int| значение * множитель
} test {
    // Тест внешней функции
    let прибавить5 = внешняяФункция(5)
    assert прибавить5(3) == 8
    assert прибавить5(10) == 15
    
    // Тест счётчика
    let mut счётчик1 = создатьСчётчик(0)
    let mut счётчик2 = создатьСчётчик(100)
    
    assert счётчик1() == 1
    assert счётчик1() == 2
    assert счётчик2() == 101
    assert счётчик1() == 3  // Независимое состояние сохраняется
    
    // Тест генератора умножителя
    let удвоитель = создатьУмножитель(2)
    let утроитель = создатьУмножитель(3)
    
    assert удвоитель(5) == 10
    assert утроитель(4) == 12
}

print("прибавить5(7) = {внешняяФункция(5)(7)}")

let mut мойСчётчик = создатьСчётчик(10)
print("Счётчик: {мойСчётчик()}, {мойСчётчик()}, {мойСчётчик()}")

let десятикратныйУмножитель = создатьУмножитель(10)
print("10 * 7 = {десятикратныйУмножитель(7)}")

Основные характеристики замыканий

  1. Захват среды: Запоминает переменные из внешних областей видимости
  2. Сохранение состояния: Поддерживает состояние между вызовами функций
  3. Отложенное выполнение: Откладывает вычисления до необходимости
  4. Повторное использование кода: Одна логика применима в разных контекстах

🎨 Различные паттерны замыканий

Захват по значению vs захват по ссылке

// Захват по значению (Copy)
function примерЗахватаЗначения() -> impl Fn() -> int {
    let значение = 42
    
    // Значение копируется в замыкание
    || значение  // Значение копируется внутрь замыкания
}

// Захват по ссылке (Borrow)
function примерЗахватаСсылки() -> impl Fn() -> int {
    let значение = 42
    
    // Захват по ссылке (когда время жизни позволяет)
    move || значение  // Передача владения ключевым словом move
}

// Захват изменяемой ссылки
function примерИзменяемогоЗахвата() -> impl FnMut() -> int {
    let mut счётчик = 0
    
    // Захват изменяемой ссылки
    move || -> int {
        счётчик += 1
        счётчик
    }
}

// Захват сложной среды
function сложнаяСреда() -> (impl Fn(int) -> int, impl Fn(int) -> int) {
    let базовоеЗначение = 10
    let множитель = 3
    let mut накопленноеЗначение = 0
    
    let функцияСложения = move |дополнительноеЗначение: int| -> int {
        накопленноеЗначение += дополнительноеЗначение
        базовоеЗначение + накопленноеЗначение
    }
    
    let функцияУмножения = |входноеЗначение: int| -> int {
        входноеЗначение * множитель
    }
    
    return (функцияСложения, функцияУмножения)
}

// Цепочка замыканий
function создатьЦепочкуФункций(начальнаяФункция: impl Fn(int) -> int) -> impl Fn(impl Fn(int) -> int) -> impl Fn(int) -> int {
    move |следующаяФункция: impl Fn(int) -> int| -> impl Fn(int) -> int {
        move |вход: int| -> int {
            следующаяФункция(начальнаяФункция(вход))
        }
    }
} test {
    // Тест захвата значения
    let замыканиеЗначения = примерЗахватаЗначения()
    assert замыканиеЗначения() == 42
    
    // Тест изменяемого захвата  
    let mut изменяемоеЗамыкание = примерИзменяемогоЗахвата()
    assert изменяемоеЗамыкание() == 1
    assert изменяемоеЗамыкание() == 2
    assert изменяемоеЗамыкание() == 3
    
    // Тест сложной среды
    let (mut функцияСложения, функцияУмножения) = сложнаяСреда()
    assert функцияСложения(5) == 15  // 10 + 5
    assert функцияСложения(3) == 18  // 10 + 5 + 3
    assert функцияУмножения(4) == 12   // 4 * 3
    
    // Тест цепочки функций
    let удвоить = |x: int| x * 2
    let прибавить10 = |x: int| x + 10
    
    let цепнаяФункция = создатьЦепочкуФункций(удвоить)(прибавить10)
    assert цепнаяФункция(5) == 20  // (5 * 2) + 10
}

let mut моёИзменяемоеЗамыкание = примерИзменяемогоЗахвата()
print("Изменяемое замыкание: {моёИзменяемоеЗамыкание()}, {моёИзменяемоеЗамыкание()}")

let (mut функцияСложения, функцияУмножения) = сложнаяСреда()
print("Сложение: {функцияСложения(7)}, Умножение: {функцияУмножения(6)}")

Функции высшего порядка и замыкания

// Функция, возвращающая функцию
function создательУсловныхФункций(условие: bool) -> impl Fn(int) -> int {
    if условие {
        |x: int| x * 2  // Удвоить
    } else {
        |x: int| x + 10  // Прибавить 10
    }
}

// Функция, принимающая функцию как параметр
function применительФункций<F, T>(значение: T, функция: F) -> T 
where
    F: Fn(T) -> T
{
    функция(значение)
}

// Композитор, объединяющий несколько функций
function композиторФункций<F, G, T>(функция1: F, функция2: G) -> impl Fn(T) -> T
where
    F: Fn(T) -> T,
    G: Fn(T) -> T,
    T: 'static
{
    move |вход: T| -> T {
        функция2(функция1(вход))
    }
}

// Реализация каррирования
function примерКаррирования(а: int) -> impl Fn(int) -> impl Fn(int) -> int {
    move |б: int| -> impl Fn(int) -> int {
        move |в: int| -> int {
            а + б + в
        }
    }
}

// Замыкание мемоизации
function мемоизация<F, T, U>(функция: F) -> impl FnMut(T) -> U
where
    F: Fn(T) -> U,
    T: Clone + std::hash::Hash + Eq,
    U: Clone,
{
    use std::collections::HashMap
    
    let mut кэш: HashMap<T, U> = HashMap::new()
    
    move |вход: T| -> U {
        match кэш.get(&вход) { case Some(результат) => return результат.clone(), case None => {} }
        
        let результат = функция(вход.clone())
        кэш.insert(вход, результат.clone())
        результат
    }
} test {
    // Тест создателя условных функций
    let функцияУдвоения = создательУсловныхФункций(true)
    let функцияСложения = создательУсловныхФункций(false)
    
    assert функцияУдвоения(5) == 10
    assert функцияСложения(5) == 15
    
    // Тест применителя функций
    let результат = применительФункций(10, |x| x * 3)
    assert результат == 30
    
    // Тест композитора функций
    let прибавить5 = |x: int| x + 5
    let умножить2 = |x: int| x * 2
    let составнаяФункция = композиторФункций(прибавить5, умножить2)
    
    assert составнаяФункция(3) == 16  // (3 + 5) * 2
    
    // Тест каррирования
    let каррированнаяФункция = примерКаррирования(1)(2)(3)
    assert каррированнаяФункция == 6  // 1 + 2 + 3
    
    // Тест мемоизации
    let mut мемоФакториал = мемоизация(|н: int| -> int {
        if н <= 1 { 1 } else { н * мемоФакториал(н - 1) }
    })
    
    assert мемоФакториал(5) == 120
}

print("Условная(true): {создательУсловныхФункций(true)(7)}")
print("Результат составной функции: {композиторФункций(|x| x + 1, |x| x * 10)(4)}")
print("Результат каррирования: {примерКаррирования(10)(20)(30)}")

Обработка событий и колбэки

// Определение типа обработчика событий
type ОбработчикСобытий<T> = Box<dyn FnMut(T)>

// Простая система событий
struct СистемаСобытий<T> {
    обработчики: Vec<ОбработчикСобытий<T>>
}

impl<T> СистемаСобытий<T>
where
    T: Clone
{
    function new() -> Self {
        СистемаСобытий {
            обработчики: Vec::new()
        }
    }
    
    // Регистрация обработчика событий
    function зарегистрироватьОбработчик<F>(&mut self, обработчик: F)
    where
        F: FnMut(T) + 'static
    {
        self.обработчики.push(Box::new(обработчик))
    }
    
    // Запуск события
    function запуститьСобытие(&mut self, данные: T) {
        for обработчик in &mut self.обработчики {
            обработчик(данные.clone())
        }
    }
}

// Симуляция асинхронной операции
function асинхроннаяОперация<F>(задержкаМс: int, колбэкЗавершения: F)
where
    F: FnOnce(string) + 'static
{
    // В реальности это было бы асинхронно, но здесь выполняем немедленно
    let результат = format!("Задача завершена (через {}мс)", задержкаМс)
    колбэкЗавершения(результат)
}

// Детектор изменения состояния
struct НаблюдательСостояния<T> {
    текущееСостояние: T,
    колбэкиИзменений: Vec<Box<dyn Fn(&T, &T)>>
}

impl<T> НаблюдательСостояния<T>
where
    T: Clone + PartialEq
{
    function new(начальноеСостояние: T) -> Self {
        НаблюдательСостояния {
            текущееСостояние: начальноеСостояние,
            колбэкиИзменений: Vec::new()
        }
    }
    
    function зарегистрироватьКолбэкИзменения<F>(&mut self, колбэк: F)
    where
        F: Fn(&T, &T) + 'static
    {
        self.колбэкиИзменений.push(Box::new(колбэк))
    }
    
    function изменитьСостояние(&mut self, новоеСостояние: T) {
        if self.текущееСостояние != новоеСостояние {
            let предыдущееСостояние = self.текущееСостояние.clone()
            self.текущееСостояние = новоеСостояние.clone()
            
            for колбэк in &self.колбэкиИзменений {
                колбэк(&предыдущееСостояние, &новоеСостояние)
            }
        }
    }
    
    function текущееЗначение(&self) -> &T {
        &self.текущееСостояние
    }
} test {
    // Тест системы событий
    let mut системаСобытий = СистемаСобытий::<string>::new()
    
    let mut полученныеСообщения: Vec<string> = Vec::new()
    
    системаСобытий.зарегистрироватьОбработчик(move |сообщение: string| {
        полученныеСообщения.push(format!("Обработчик1: {}", сообщение))
    })
    
    системаСобытий.зарегистрироватьОбработчик(|сообщение: string| {
        println!("Обработчик2 получил: {}", сообщение)
    })
    
    системаСобытий.запуститьСобытие("Тестовое сообщение".to_string())
    
    // Тест наблюдателя состояния
    let mut наблюдательТемпературы = НаблюдательСостояния::new(20.0)
    
    let mut журналИзменений: Vec<string> = Vec::new()
    
    наблюдательТемпературы.зарегистрироватьКолбэкИзменения(move |предыдущее: &f64, новоеЗначение: &f64| {
        журналИзменений.push(format!("Изменение температуры: {}°C → {}°C", предыдущее, новоеЗначение))
    })
    
    наблюдательТемпературы.изменитьСостояние(25.0)
    наблюдательТемпературы.изменитьСостояние(30.0)
    
    assert *наблюдательТемпературы.текущееЗначение() == 30.0
}

// Пример использования
let mut событиеКлика = СистемаСобытий::<string>::new()

событиеКлика.зарегистрироватьОбработчик(|имяКнопки: string| {
    print!("Кнопка '{}' была нажата!", имяКнопки)
})

событиеКлика.запуститьСобытие("ОК".to_string())

// Пример асинхронной операции
асинхроннаяОперация(1000, |результат: string| {
    print!("Результат асинхронной операции: {}", результат)
})

🚀 Практические применения замыканий

Паттерны функционального программирования

// Функциональный конвейер
function конвейер<T>(начальноеЗначение: T) -> СтроительКонвейера<T> {
    СтроительКонвейера::new(начальноеЗначение)
}

struct СтроительКонвейера<T> {
    значение: T
}

impl<T> СтроительКонвейера<T> {
    function new(значение: T) -> Self {
        СтроительКонвейера { значение }
    }
    
    function map<U, F>(self, функция: F) -> СтроительКонвейера<U>
    where
        F: FnOnce(T) -> U
    {
        СтроительКонвейера::new(функция(self.значение))
    }
    
    function filter<F>(self, условие: F) -> Option<СтроительКонвейера<T>>
    where
        F: FnOnce(&T) -> bool
    {
        if условие(&self.значение) {
            Some(self)
        } else {
            None
        }
    }
    
    function fold<U, F>(self, начальноеЗначение: U, функция: F) -> U
    where
        F: FnOnce(U, T) -> U
    {
        функция(начальноеЗначение, self.значение)
    }
    
    function finish(self) -> T {
        self.значение
    }
}

// Утилита обработки массивов
function процессорМассивов<T>() -> ПроцессорМассивов<T> {
    ПроцессорМассивов::new()
}

struct ПроцессорМассивов<T> {
    _phantom: std::marker::PhantomData<T>
}

impl<T> ПроцессорМассивов<T> {
    function new() -> Self {
        ПроцессорМассивов { _phantom: std::marker::PhantomData }
    }
    
    function map<U, F>(&self, массив: Vec<T>, функция: F) -> Vec<U>
    where
        F: Fn(T) -> U
    {
        массив.into_iter().map(функция).collect()
    }
    
    function filter<F>(&self, массив: Vec<T>, условие: F) -> Vec<T>
    where
        F: Fn(&T) -> bool
    {
        массив.into_iter().filter(условие).collect()
    }
    
    function reduce<F>(&self, массив: Vec<T>, функция: F) -> Option<T>
    where
        F: Fn(T, T) -> T
    {
        массив.into_iter().reduce(функция)
    }
    
    function fold<U, F>(&self, массив: Vec<T>, начальноеЗначение: U, функция: F) -> U
    where
        F: Fn(U, T) -> U
    {
        массив.into_iter().fold(начальноеЗначение, функция)
    }
}

// Цепочка условного выполнения
function еслиУсловие<F>(условие: bool, функцияВыполнения: F) -> УсловноеВыполнение<F>
where
    F: FnOnce()
{
    УсловноеВыполнение { условие, функцияВыполнения: Some(функцияВыполнения) }
}

struct УсловноеВыполнение<F>
where
    F: FnOnce()
{
    условие: bool,
    функцияВыполнения: Option<F>
}

impl<F> УсловноеВыполнение<F>
where
    F: FnOnce()
{
    function иначе<G>(mut self, функцияИначе: G)
    where
        G: FnOnce()
    {
        if self.условие {
            match self.функцияВыполнения.take() { case Some(функция) => функция(), case None => {} }
        } else {
            функцияИначе()
        }
    }
    
    function выполнить(mut self) {
        if self.условие {
            match self.функцияВыполнения.take() { case Some(функция) => функция(), case None => {} }
        }
    }
} test {
    // Тест конвейера
    let результат = конвейер(10)
        .map(|x| x * 2)
        .map(|x| x + 5)
        .filter(|&x| x > 20)
        .map(|x| x.to_string())
        .finish()
    
    assert результат == Some("25".to_string())
    
    // Тест процессора массивов
    let процессорМассивов = процессорМассивов::<i32>()
    let числа = vec![1, 2, 3, 4, 5]
    
    let квадраты = процессорМассивов.map(числа.clone(), |x| x * x)
    assert квадраты == vec![1, 4, 9, 16, 25]
    
    let чётные = процессорМассивов.filter(числа.clone(), |&x| x % 2 == 0)
    assert чётные == vec![2, 4]
    
    let сумма = процессорМассивов.fold(числа, 0, |акк, x| акк + x)
    assert сумма == 15
    
    // Тест условного выполнения
    let mut выполнено = false
    
    еслиУсловие(true, || {
        выполнено = true
    }).выполнить()
    
    assert выполнено == true
}

// Пример использования
let результатОбработки = конвейер(vec![1, 2, 3, 4, 5])
    .map(|массив| процессорМассивов::<i32>().map(массив, |x| x * 2))
    .map(|массив| процессорМассивов::<i32>().filter(массив, |&x| x > 5))
    .finish()

print!("Обработанный массив: {:?}", результатОбработки)

еслиУсловие(результатОбработки.len() > 2, || {
    print!("Массив достаточно большой!")
}).иначе(|| {
    print!("Массив слишком мал.")
})

Ленивое вычисление и потоки

// Последовательность ленивого вычисления
struct ЛениваяПоследовательность<T, F>
where
    F: Fn() -> Option<T>
{
    функцияГенератор: F
}

impl<T, F> ЛениваяПоследовательность<T, F>
where
    F: Fn() -> Option<T>
{
    function new(функцияГенератор: F) -> Self {
        ЛениваяПоследовательность { функцияГенератор }
    }
    
    function take(self, количество: usize) -> Vec<T> {
        let mut результат = Vec::new()
        
        for _ in 0..количество {
            match (self.функцияГенератор)() { case Some(значение) => результат.push(значение), case None => break }
        }
        
        результат
    }
}

// Генератор бесконечной последовательности
function бесконечнаяПоследовательность(начало: int, шаг: int) -> impl Fn() -> Option<int> {
    let mut текущее = начало
    
    move || -> Option<int> {
        let значение = текущее
        текущее += шаг
        Some(значение)
    }
}

// Генератор последовательности Фибоначчи
function генераторФибоначчи() -> impl Fn() -> Option<int> {
    let mut а = 0
    let mut б = 1
    
    move || -> Option<int> {
        let текущее = а
        let следующее = а + б
        а = б
        б = следующее
        Some(текущее)
    }
}

// Условная бесконечная последовательность
function условнаяПоследовательность<F, P>(функцияГенератор: F, условие: P) -> impl Fn() -> Option<int>
where
    F: Fn() -> int,
    P: Fn(int) -> bool
{
    move || -> Option<int> {
        loop {
            let значение = функцияГенератор()
            if условие(значение) {
                return Some(значение)
            }
        }
    }
}

// Процессор потоков
struct Поток<T> {
    данные: Vec<T>
}

impl<T> Поток<T>
where
    T: Clone
{
    function from(данные: Vec<T>) -> Self {
        Поток { данные }
    }
    
    function map<U, F>(self, функция: F) -> Поток<U>
    where
        F: Fn(T) -> U
    {
        Поток {
            данные: self.данные.into_iter().map(функция).collect()
        }
    }
    
    function filter<F>(self, условие: F) -> Поток<T>
    where
        F: Fn(&T) -> bool
    {
        Поток {
            данные: self.данные.into_iter().filter(условие).collect()
        }
    }
    
    function take(self, количество: usize) -> Поток<T> {
        Поток {
            данные: self.данные.into_iter().take(количество).collect()
        }
    }
    
    function collect(self) -> Vec<T> {
        self.данные
    }
} test {
    // Тест бесконечной последовательности
    let арифметическаяПоследовательность = бесконечнаяПоследовательность(1, 2)  // 1, 3, 5, 7, ...
    let первыеПять = (0..5).map(|_| арифметическаяПоследовательность()).collect::<Vec<_>>()
    
    assert первыеПять == vec![Some(1), Some(3), Some(5), Some(7), Some(9)]
    
    // Тест Фибоначчи
    let фибоначчи = генераторФибоначчи()
    let первыеШестьФибоначчи: Vec<_> = (0..6).map(|_| фибоначчи()).collect()
    
    assert первыеШестьФибоначчи == vec![Some(0), Some(1), Some(1), Some(2), Some(3), Some(5)]
    
    // Тест обработки потоков
    let результат = Поток::from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
        .filter(|&x| x % 2 == 0)  // Только чётные числа
        .map(|x| x * x)           // Квадрат
        .take(3)                  // Первые 3
        .collect()
    
    assert результат == vec![4, 16, 36]  // 2², 4², 6²
}

// Пример использования
let генераторНечётных = бесконечнаяПоследовательность(1, 2)
print!("Первые 10 нечётных чисел: {:?}", (0..<10).map(|_| генераторНечётных()).collect::<Vec<_>>())

let фибоначчи = генераторФибоначчи()
print!("Последовательность Фибоначчи: {:?}", (0..8).map(|_| фибоначчи()).collect::<Vec<_>>())

let результатПотока = Поток::from((1..=20).collect())
    .filter(|&x| x % 3 == 0)    // Кратные 3
    .map(|x| format!("{}-й", x))  // Преобразование в строку
    .take(4)
    .collect()

print!("Кратные 3: {:?}", результатПотока)

🎯 Продвинутые техники замыканий

Динамическое создание функций

// Генератор функций во время выполнения
enum ТипОперации {
    Сложение,
    Вычитание,
    Умножение,
    Деление
}

function создатьФункциюОперации(операция: ТипОперации, операнд: f64) -> Box<dyn Fn(f64) -> f64> {
    match операция {
        case ТипОперации::Сложение => Box::new(move |x| x + операнд),
        case ТипОперации::Вычитание => Box::new(move |x| x - операнд),
        case ТипОперации::Умножение => Box::new(move |x| x * операнд),
        case ТипОперации::Деление => Box::new(move |x| {
            if операнд != 0.0 { x / операнд } else { f64::NAN }
        })
    }
}

// Условная цепочка функций
struct ЦепочкаФункций<T> {
    функции: Vec<Box<dyn Fn(T) -> T>>
}

impl<T> ЦепочкаФункций<T>
where
    T: 'static
{
    function new() -> Self {
        ЦепочкаФункций { функции: Vec::new() }
    }
    
    function добавить<F>(mut self, функция: F) -> Self
    where
        F: Fn(T) -> T + 'static
    {
        self.функции.push(Box::new(функция))
        self
    }
    
    function условноДобавить<F>(mut self, условие: bool, функция: F) -> Self
    where
        F: Fn(T) -> T + 'static
    {
        if условие {
            self.функции.push(Box::new(функция))
        }
        self
    }
    
    function выполнить(self, начальноеЗначение: T) -> T {
        self.функции.into_iter().fold(начальноеЗначение, |значение, функция| функция(значение))
    }
}

// Настраиваемый генератор валидаторов
struct ПравилоВалидации<T> {
    имя: string,
    функцияВалидации: Box<dyn Fn(&T) -> bool>
}

struct Валидатор<T> {
    правила: Vec<ПравилоВалидации<T>>
}

impl<T> Валидатор<T> {
    function new() -> Self {
        Валидатор { правила: Vec::new() }
    }
    
    function добавитьПравило<F>(mut self, имя: string, функцияВалидации: F) -> Self
    where
        F: Fn(&T) -> bool + 'static
    {
        self.правила.push(ПравилоВалидации { 
            имя, 
            функцияВалидации: Box::new(функцияВалидации) 
        })
        self
    }
    
    function валидировать(&self, значение: &T) -> Result<(), Vec<string>> {
        let mut ошибки = Vec::new()
        
        for правило in &self.правила {
            if !(правило.функцияВалидации)(значение) {
                ошибки.push(правило.имя.clone())
            }
        }
        
        if ошибки.is_empty() {
            Ok(())
        } else {
            Err(ошибки)
        }
    }
} test {
    // Тест динамического создания функций
    let прибавить10 = создатьФункциюОперации(ТипОперации::Сложение, 10.0)
    let умножить2 = создатьФункциюОперации(ТипОперации::Умножение, 2.0)
    
    assert прибавить10(5.0) == 15.0
    assert умножить2(7.0) == 14.0
    
    // Тест цепочки функций
    let цепочка = ЦепочкаФункций::new()
        .добавить(|x: i32| x + 1)
        .условноДобавить(true, |x: i32| x * 2)
        .добавить(|x: i32| x - 3)
    
    let результат = цепочка.выполнить(5)  // ((5 + 1) * 2) - 3 = 9
    assert результат == 9
    
    // Тест валидатора
    let валидаторЧисел = Валидатор::new()
        .добавитьПравило("должно быть положительным".to_string(), |&x: &i32| x > 0)
        .добавитьПравило("должно быть меньше 100".to_string(), |&x: &i32| x < 100)
        .добавитьПравило("должно быть чётным".to_string(), |&x: &i32| x % 2 == 0)
    
    assert валидаторЧисел.валидировать(&50).is_ok()
    assert валидаторЧисел.валидировать(&-5).is_err()
    assert валидаторЧисел.валидировать(&51).is_err()  // Не проходит, потому что нечётное
}

// Пример использования
let цепочкаВычислений = ЦепочкаФункций::new()
    .добавить(|x: f64| x * 1.5)        // Увеличение на 50%
    .условноДобавить(true, |x| x + 10.0) // Прибавить 10
    .добавить(|x| x.round())            // Округлить

let финальныйРезультат = цепочкаВычислений.выполнить(7.3)
print!("Результат вычисления: {}", финальныйРезультат)

let валидаторСтрок = Валидатор::new()
    .добавитьПравило("не пустая".to_string(), |s: &string| !s.is_empty())
    .добавитьПравило("минимальная длина".to_string(), |s: &string| s.len() >= 3)
    .добавитьПравило("содержит спецсимвол".to_string(), |s: &string| s.contains('@'))

match валидаторСтрок.валидировать(&"test@example.com".to_string()) {
    case Ok(()) => print!("Валидация успешна!"),
    case Err(ошибки) => print!("Валидация не пройдена: {:?}", ошибки)
}

Система плагинов

// Интерфейс плагина
trait Плагин {
    function имя(&self) -> &str
    function выполнить(&self, вход: &str) -> string
}

// Плагин на основе замыкания
struct ПлагинЗамыкание<F>
where
    F: Fn(&str) -> string
{
    имя: string,
    функцияВыполнения: F
}

impl<F> ПлагинЗамыкание<F>
where
    F: Fn(&str) -> string
{
    function new(имя: string, функцияВыполнения: F) -> Self {
        ПлагинЗамыкание { имя, функцияВыполнения }
    }
}

impl<F> Плагин for ПлагинЗамыкание<F>
where
    F: Fn(&str) -> string
{
    function имя(&self) -> &str {
        &self.имя
    }
    
    function выполнить(&self, вход: &str) -> string {
        (self.функцияВыполнения)(вход)
    }
}

// Менеджер плагинов
struct МенеджерПлагинов {
    плагины: Vec<Box<dyn Плагин>>
}

impl МенеджерПлагинов {
    function new() -> Self {
        МенеджерПлагинов { плагины: Vec::new() }
    }
    
    function зарегистрироватьПлагин<P>(mut self, плагин: P) -> Self
    where
        P: Плагин + 'static
    {
        self.плагины.push(Box::new(плагин))
        self
    }
    
    function выполнитьВсеПлагины(&self, вход: &str) -> Vec<(string, string)> {
        self.плагины
            .iter()
            .map(|плагин| (плагин.имя().to_string(), плагин.выполнить(вход)))
            .collect()
    }
    
    function найтиПлагин(&self, имя: &str) -> Option<&dyn Плагин> {
        self.плагины
            .iter()
            .find(|плагин| плагин.имя() == имя)
            .map(|плагин| плагин.as_ref())
    }
}

// Система промежуточного ПО
type ПромежуточноеПО<T> = Box<dyn Fn(T, Box<dyn Fn(T) -> T>) -> T>

struct ЦепочкаПромежуточногоПО<T> {
    промежуточноеПО: Vec<ПромежуточноеПО<T>>
}

impl<T> ЦепочкаПромежуточногоПО<T>
where
    T: 'static
{
    function new() -> Self {
        ЦепочкаПромежуточногоПО { промежуточноеПО: Vec::new() }
    }
    
    function добавитьПромежуточноеПО<F>(mut self, промежуточноеПО: F) -> Self
    where
        F: Fn(T, Box<dyn Fn(T) -> T>) -> T + 'static
    {
        self.промежуточноеПО.push(Box::new(промежуточноеПО))
        self
    }
    
    function выполнить<F>(self, вход: T, финальныйОбработчик: F) -> T
    where
        F: Fn(T) -> T + 'static
    {
        let mut цепочка = Box::new(финальныйОбработчик) as Box<dyn Fn(T) -> T>
        
        for промежуточноеПО in self.промежуточноеПО.into_iter().rev() {
            let предыдущаяЦепочка = цепочка
            цепочка = Box::new(move |вход| промежуточноеПО(вход, предыдущаяЦепочка))
        }
        
        цепочка(вход)
    }
} test {
    // Тест системы плагинов
    let менеджер = МенеджерПлагинов::new()
        .зарегистрироватьПлагин(ПлагинЗамыкание::new(
            "верхний регистр".to_string(),
            |текст| текст.to_uppercase()
        ))
        .зарегистрироватьПлагин(ПлагинЗамыкание::new(
            "счётчик длины".to_string(),
            |текст| format!("Длина: {}", текст.len())
        ))
        .зарегистрироватьПлагин(ПлагинЗамыкание::new(
            "обратный порядок".to_string(),
            |текст| текст.chars().rev().collect()
        ))
    
    let результаты = менеджер.выполнитьВсеПлагины("привет мир")
    assert результаты.len() == 3
    
    match менеджер.найтиПлагин("верхний регистр") { case Some(плагинВерхнегоРегистра) => assert плагинВерхнегоРегистра.выполнить("тест") == "ТЕСТ", case None => {} }
    
    // Тест промежуточного ПО
    let цепочка = ЦепочкаПромежуточногоПО::new()
        .добавитьПромежуточноеПО(|значение: i32, следующее| {
            print!("Промежуточное ПО 1: вход {}", значение)
            let результат = следующее(значение + 1)
            print!("Промежуточное ПО 1: выход {}", результат)
            результат
        })
        .добавитьПромежуточноеПО(|значение, следующее| {
            print!("Промежуточное ПО 2: вход {}", значение)
            let результат = следующее(значение * 2)
            print!("Промежуточное ПО 2: выход {}", результат)
            результат
        })
    
    let финальныйРезультат = цепочка.выполнить(5, |значение| {
        print!("Финальный обработчик: {}", значение)
        значение + 10
    })
    
    assert финальныйРезультат == 22  // ((5 + 1) * 2) + 10
}

// Пример использования
let менеджерОбработкиТекста = МенеджерПлагинов::new()
    .зарегистрироватьПлагин(ПлагинЗамыкание::new(
        "HTML экранирование".to_string(),
        |текст| текст.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
    ))
    .зарегистрироватьПлагин(ПлагинЗамыкание::new(
        "выделение markdown".to_string(),
        |текст| format!("**{}**", текст)
    ))

let результатыОбработки = менеджерОбработкиТекста.выполнитьВсеПлагины("Привет <мир> & друзья!")

for (имяПлагина, результат) in результатыОбработки {
    print!("{}: {}", имяПлагина, результат)
}

🔍 Оптимизация производительности замыканий

Эффективные по памяти замыкания

// Замыкание на основе ссылок (эффективно по памяти)
function замыканиеНаОснореСсылок(данные: &[i32]) -> impl Fn(usize) -> Option<i32> + '_ {
    move |индекс| данные.get(индекс).copied()
}

// Использование умных указателей
use std::rc::Rc
use std::sync::Arc

function создатьОбщееЗамыкание(общиеДанные: Rc<Vec<i32>>) -> impl Fn(usize) -> Option<i32> {
    move |индекс| общиеДанные.get(индекс).copied()
}

function создатьПотокобезопасноеЗамыкание(общиеДанные: Arc<Vec<i32>>) -> impl Fn(usize) -> Option<i32> + Send + Sync {
    move |индекс| общиеДанные.get(индекс).copied()
}

// Ленивая инициализация замыкания
struct ЛениваяИнициализация<T, F>
where
    F: FnOnce() -> T
{
    функцияИнициализации: Option<F>,
    значение: Option<T>
}

impl<T, F> ЛениваяИнициализация<T, F>
where
    F: FnOnce() -> T
{
    function new(функцияИнициализации: F) -> Self {
        ЛениваяИнициализация {
            функцияИнициализации: Some(функцияИнициализации),
            значение: None
        }
    }
    
    function get(&mut self) -> &T {
        if self.значение.is_none() {
            let функцияИнициализации = self.функцияИнициализации.take().unwrap()
            self.значение = Some(функцияИнициализации())
        }
        self.значение.as_ref().unwrap()
    }
}

// Пулинг замыканий
struct ПулЗамыканий<F, T, U>
where
    F: Fn(T) -> U
{
    функции: Vec<F>,
    текущийИндекс: usize
}

impl<F, T, U> ПулЗамыканий<F, T, U>
where
    F: Fn(T) -> U + Clone
{
    function new(функция: F, размер: usize) -> Self {
        ПулЗамыканий {
            функции: vec![функция; размер],
            текущийИндекс: 0
        }
    }
    
    function выполнить(&mut self, вход: T) -> U {
        let функция = &self.функции[self.текущийИндекс]
        self.текущийИндекс = (self.текущийИндекс + 1) % self.функции.len()
        функция(вход)
    }
} test {
    // Тест общего замыкания
    let данные = Rc::new(vec![1, 2, 3, 4, 5])
    let замыкание1 = создатьОбщееЗамыкание(данные.clone())
    let замыкание2 = создатьОбщееЗамыкание(данные.clone())
    
    assert замыкание1(0) == Some(1)
    assert замыкание2(4) == Some(5)
    
    // Тест ленивой инициализации
    let mut ленивоеЗначение = ЛениваяИнициализация::new(|| {
        print!("Выполнено дорогое вычисление")
        42
    })
    
    assert *ленивоеЗначение.get() == 42
    assert *ленивоеЗначение.get() == 42  // Нет вычисления при втором вызове
    
    // Тест пула замыканий
    let mut пул = ПулЗамыканий::new(|x: i32| x * 2, 3)
    
    assert пул.выполнить(5) == 10
    assert пул.выполнить(3) == 6
}

// Замыкание для измерения производительности
function бенчмарк<F, T>(имя: &str, функция: F, вход: T) -> T
where
    F: FnOnce(T) -> T
{
    use std::time::Instant
    
    let времяНачала = Instant::now()
    let результат = функция(вход)
    let прошедшееВремя = времяНачала.elapsed()
    
    print!("{} время выполнения: {:?}", имя, прошедшееВремя)
    результат
}

// Кэшированное замыкание
use std::collections::HashMap

struct КэшированноеЗамыкание<F, K, V>
where
    F: Fn(K) -> V,
    K: Clone + std::hash::Hash + Eq,
    V: Clone
{
    функция: F,
    кэш: HashMap<K, V>
}

impl<F, K, V> КэшированноеЗамыкание<F, K, V>
where
    F: Fn(K) -> V,
    K: Clone + std::hash::Hash + Eq,
    V: Clone
{
    function new(функция: F) -> Self {
        КэшированноеЗамыкание {
            функция,
            кэш: HashMap::new()
        }
    }
    
    function выполнить(&mut self, ключ: K) -> V {
        match self.кэш.get(&ключ) { case Some(значение) => return значение.clone(), case None => {} }
        
        let результат = (self.функция)(ключ.clone())
        self.кэш.insert(ключ, результат.clone())
        результат
    }
    
    function размерКэша(&self) -> usize {
        self.кэш.len()
    }
    
    function очиститьКэш(&mut self) {
        self.кэш.clear()
    }
}

// Пример использования
let общийВектор = Arc::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let замыканиеДоступа = создатьПотокобезопасноеЗамыкание(общийВектор)

print!("Доступ к значению: {:?}", замыканиеДоступа(3))

let mut кэшФибоначчи = КэшированноеЗамыкание::new(|н: i32| -> i64 {
    if н <= 1 { н as i64 } else { 
        // В реальности это должно использовать кэш рекурсивно,
        // но здесь упрощённая версия
as i64).pow(2)  // Простое вычисление для примера
    }
})

бенчмарк("Вычисление Фибоначчи", |_| {
    for и in 1..=20 {
        кэшФибоначчи.выполнить(и)
    }
}, ())

print!("Размер кэша: {}", кэшФибоначчи.размерКэша())

🎯 Мастерство замыканий

Замыкания — одна из самых мощных возможностей Топаз:

✅ Когда использовать замыкания:

  • Колбэк-функции и обработка событий
  • Реализация функций высшего порядка
  • Когда нужна инкапсуляция состояния
  • Ленивое выполнение и частичное применение

⚠️ Меры предосторожности:

  • Предотвращение утечек памяти (избегание циклических ссылок)
  • Соображения производительности (избегание ненужного создания замыканий)
  • Управление временем жизни (выбор подходящих методов захвата)
  • Осознание сложности отладки

🚀 Преимущества замыканий Топаз:

  • Гарантированная типобезопасность
  • Автоматическое управление памятью
  • Поддержка различных методов захвата
  • Идеальная поддержка парадигмы функционального программирования

Пишите более выразительный код с замыканиями! ✨🚀