Что означает оператор r#""# в Rust для строковых литералов?
Что такое сырые строковые литералы (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 обрабатывает его следующим образом:
- Если встречает
r, то включает режим "сырой" строки (отключает escape-последовательности) - Количество решёток
#определяет, какой маркер считать концом строки. Дляr#"..."#конец — это"#, дляr##"..."##—"##и т.д.
Это особенно полезно при работе с шаблонами или кодом, который генерируется автоматически. Например, при написании макросов:
macro_rules! my_macro {
($x:expr) => {
let s = r###"Код с "кавычками" и даже "###" внутри"###;
};
}
Также это удобно для тестирования, когда нужно вставить JSON или XML прямо в код без дополнительных преобразований. Лично я часто использую r#"..."# для написания SQL-запросов с кавычками внутри.
Совет: Если вы не уверены, сколько решёток нужно, начните с одной r#. Если внутри строки есть "#, компилятор выдаст ошибку, и вы сможете увеличить количество решёток. Это безопасно — компилятор Rust всегда подскажет правильный синтаксис.