Привязка образца @

В языке Rust оператор @ называется "bind operator" (оператор привязки) и используется для создания привязки значения к переменной внутри паттерн-матчинга.

Основная концепция

Оператор @ позволяет:

  • Проверить, соответствует ли значение паттерну
  • Одновременно привязать это значение к переменной

Синтаксис

#![allow(unused)]
fn main() {
переменная @ паттерн
}

Примеры использования

1. Привязка в диапазонах

fn check_number(n: u32) {
    match n {
        x @ 0..=9 => println!("Одна цифра: {}", x),
        x @ 10..=99 => println!("Две цифры: {}", x),
        x @ 100..=999 => println!("Три цифры: {}", x),
        _ => println!("Большое число"),
    }
}

fn main() {
    check_number(5);    // Одна цифра: 5
    check_number(42);   // Две цифры: 42
    check_number(123);  // Три цифры: 123
}

2. Работа с перечислениями (enum)

#![allow(unused)]
fn main() {
enum Message {
    Text(String),
    Number(i32),
    Coordinate { x: i32, y: i32 },
}

fn process_message(msg: Message) {
    match msg {
        Message::Text(text) @ Message::Text(_) => {
            println!("Текстовое сообщение: {}", text)
        },
        Message::Number(n @ 0..=100) => {
            println!("Число в диапазоне 0-100: {}", n)
        },
        Message::Coordinate { x, y } @ Message::Coordinate { x: 0..=10, y: 0..=10 } => {
            println!("Координата в квадрате 10x10: ({}, {})", x, y)
        },
        _ => println!("Другое сообщение"),
    }
}
}

3. Сложные паттерны с условиями

#![allow(unused)]
fn main() {
fn process_value(val: Option<i32>) {
    match val {
        Some(x @ 1..=10) if x % 2 == 0 => {
            println!("Четное число от 1 до 10: {}", x)
        },
        Some(x @ 1..=10) => {
            println!("Нечетное число от 1 до 10: {}", x)
        },
        Some(x) => {
            println!("Другое число: {}", x)
        },
        None => println!("Нет значения"),
    }
}
}

4. Работа со структурами

#![allow(unused)]
fn main() {
struct Point {
    x: i32,
    y: i32,
}

fn check_point(p: Point) {
    match p {
        point @ Point { x: 0..=5, y: 0..=5 } => {
            println!("Точка в квадрате 5x5: ({}, {})", point.x, point.y)
        },
        Point { x, y } => {
            println!("Точка вне квадрата: ({}, {})", x, y)
        },
    }
}
}

5. Вложенные паттерны

#![allow(unused)]
fn main() {
fn process_nested(value: Option<Option<i32>>) {
    match value {
        Some(inner @ Some(1..=10)) => {
            println!("Внутреннее значение: {:?}", inner)
        },
        Some(Some(x)) => {
            println!("Другое значение: {}", x)
        },
        Some(None) => println!("Внутренний None"),
        None => println!("Внешний None"),
    }
}
}

Преимущества использования @

  1. Избегание повторного вычисления - значение вычисляется только один раз
  2. Улучшенная читаемость - ясное указание на то, что значение используется в нескольких местах
  3. Более выразительный код - явно показывает связь между паттерном и привязкой

Когда использовать

Оператор @ особенно полезен когда:

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

Этот оператор делает код более выразительным и эффективным в ситуациях сложного паттерн-матчинга.