Avatar ·

Что означает оператор r#""# в Rust для строковых литералов?

Привет, коллеги! Я недавно начал изучать Rust и столкнулся с синтаксисом, который мне совершенно непонятен. В одном проекте я увидел такой код: ```rust let json = r#"{"name": "John", "age": 30}"#; let path = r"C:\Program Files\MyApp"; let regex = r"\d{3}-\d{2}-\d{4}"; ``` Я понимаю, что `r` перед строкой — это raw string literal (сырая строка), которая не обрабатывает escape-последовательности. Но что означает `r#""#`? Зачем нужны решётки `#` вокруг кавычек? И почему их может быть несколько, например `r##"..."##`? Я попробовал заменить `r#"..."#` на обычный `r"..."`, но компилятор выдал ошибку. В официальной документации нашёл упоминание, что это связано с экранированием кавычек внутри строки, но примеров было мало. Конкретно меня интересует: 1. Как работает `r#""#` и чем отличается от `r""`? 2. Зачем может потребоваться несколько решёток, например `r###"..."###`? 3. Есть ли альтернативы этому синтаксису? Буду благодарен за подробное объяснение с примерами. Заранее спасибо! <<>>

Что такое сырые строковые литералы (raw string literals) в Rust?

Синтаксис r#"..."# в Rust — это сырой строковый литерал с возможностью включения кавычек. Обычный сырой литерал r"..." уже отключает обработку escape-последовательностей (например, \n будет восприниматься как два символа: обратный слеш и 'n', а не как перевод строки). Но что делать, если внутри строки нужно использовать кавычки "?

Здесь и приходит на помощь синтаксис с решётками. Давайте разберём по порядку:

1. Обычный сырой литерал r"..."

let s = r"C:\Users\name";  // эквивалентно "C:\\Users\\name"
println!("{}", s); // C:\Users\name

Этот синтаксис удобен для путей Windows, регулярных выражений и JSON. Но если внутри строки есть кавычка, компилятор не поймёт, где конец строки:

// Ошибка! Компилятор видит кавычку и думает, что строка закончилась
let json = r"{"name": "John"}"; // Ошибка компиляции

2. Синтаксис с решётками r#"..."#

Решётки # вокруг кавычек меняют маркер начала/конца строки. Вместо простой кавычки " компилятор ищет последовательность "# для завершения строки. Это позволяет использовать обычные кавычки внутри:

let json = r#"{"name": "John", "age": 30}"#;
println!("{}", json); // {"name": "John", "age": 30}

Теперь кавычки внутри строки воспринимаются как обычные символы, а не как конец литерала.

3. Множественные решётки r##"..."##

Если внутри строки сама встречается последовательность "#, нужно увеличить количество решёток:

let s = r##"Он сказал: "Привет#" и ушёл"##;
// Строка содержит: Он сказал: "Привет#" и ушёл
println!("{}", s);

Количество решёток в начале и конце должно совпадать. Можно использовать от 0 до 255 решёток:

// Если внутри есть "##, используем r###...###
let complex = r###"Текст с "кавычками" и ## и даже "###" и ещё #"###;
// Внутри строки: Текст с "кавычками" и ## и даже "###" и ещё #

Практические примеры

  • Регулярные выражения: r"\d{3}-\d{2}-\d{4}" — без экранирования обратных слешей
  • JSON: r#"{"key": "value"}"# — удобно для тестов
  • SQL запросы: r#"SELECT * FROM users WHERE name = "John""#
  • HTML/XML: r#"<div class="container">"#

Альтернативы

Если строки короткие, можно использовать экранирование кавычек в обычной строке: "{\"name\": \"John\"}". Но для длинных строк с множеством кавычек сырые литералы с решётками гораздо читаемее.

Важно: Синтаксис r#""# — это не оператор, а часть синтаксиса строковых литералов. Он работает только на этапе компиляции и не влияет на производительность.

<<>>

Дополнение: как это работает "под капотом"

Синтаксис r# — это не оператор, а модификатор строкового литерала. Компилятор Rust обрабатывает его следующим образом:

  1. Если встречает r, то включает режим "сырой" строки (отключает escape-последовательности)
  2. Количество решёток # определяет, какой маркер считать концом строки. Для r#"..."# конец — это "#, для r##"..."## — "## и т.д.

Это особенно полезно при работе с шаблонами или кодом, который генерируется автоматически. Например, при написании макросов:

macro_rules! my_macro {
    ($x:expr) => {
        let s = r###"Код с "кавычками" и даже "###" внутри"###;
    };
}

Также это удобно для тестирования, когда нужно вставить JSON или XML прямо в код без дополнительных преобразований. Лично я часто использую r#"..."# для написания SQL-запросов с кавычками внутри.

Совет: Если вы не уверены, сколько решёток нужно, начните с одной r#. Если внутри строки есть "#, компилятор выдаст ошибку, и вы сможете увеличить количество решёток. Это безопасно — компилятор Rust всегда подскажет правильный синтаксис.