Как в Rust объявить многострочную строковую литерал? Синтаксис и экранирование
Основной способ: сырые строки с префиксом r
В Rust для многострочных строковых литералов используется синтаксис сырых строк (raw string literals). Он позволяет включать переносы строк и любые символы без экранирования. Базовый синтаксис:
let multi = r"Первая строка
Вторая строка
Третья строка";
Однако в таком виде строка не будет содержать символы переноса строк в самом литерале — они будут интерпретироваться как часть текста. Если вам нужны именно переносы строк (как в примере с SQL), используйте \n внутри сырой строки — но это неудобно. Правильный подход — использовать сырые строки с хешами для гибкости.
Синтаксис с хешами r#"..."#
Самый популярный способ для многострочных литералов — использовать r#"..."#. Он позволяет включать переносы строк и кавычки без экранирования:
let sql = r#"SELECT * FROM users
WHERE age > 18
ORDER BY name"#;
println!("{}", sql);
// Вывод:
// SELECT * FROM users
// WHERE age > 18
// ORDER BY name
Если внутри строки встречаются символы "#, можно добавить больше хешей: r##"..."##, r###"..."### и так далее. Это решает проблему вложенных кавычек.
Идиоматичный подход для длинных текстов
Для SQL, JSON или конфигов лучше использовать сырые строки с хешами. Пример с JSON:
let json = r#"{
"name": "Alice",
"age": 30,
"city": "New York"
}"#;
Альтернатива: конкатенация строк
Если вам нужно объединить строки без лишних переносов, можно использовать конкатенацию с помощью + или format!:
let long = "Первая часть "
"вторая часть "
"третья часть";
// Это работает благодаря конкатенации литералов на этапе компиляции
Обратите внимание: пробел в конце каждой строки сохраняется. Если нужно избежать пробелов, используйте явный \n внутри строк.
Важные замечания
- Сырые строки не поддерживают escape-последовательности (
\n,\tи т.д.) — они воспринимаются буквально. Если вам нужны управляющие символы, используйте обычные строки с\n. - Для очень длинных строк (например, HTML-шаблонов) рассмотрите использование макроса
include_str!для загрузки содержимого из внешнего файла. - В Rust 2021 edition появилась возможность использовать
r#внутри макросов, но для литералов это не требуется.
Практический совет
Если вы пишете SQL-запрос, лучше вынести его в отдельный файл и использовать include_str!:
let query = include_str!("query.sql");
// query.sql:
// SELECT * FROM users WHERE age > 18 ORDER BY name;
Это улучшает читаемость и позволяет использовать подсветку синтаксиса SQL в редакторе.
<<Использование макроса concat! для сборки строк
Если вам нужно объединить несколько строковых литералов без лишних пробелов и переносов, можно использовать макрос concat!. Он работает на этапе компиляции и не создаёт промежуточных строк:
let text = concat!(
"Первая строка",
"Вторая строка",
"Третья строка"
);
// Результат: "Первая строкаВторая строкаТретья строка"
Этот способ полезен, когда вы хотите разбить длинную строку на логические части, но не хотите вставлять переносы строк. Если переносы всё же нужны, добавьте "\n" между частями:
let text = concat!(
"Первая строка",
"\n",
"Вторая строка"
);
Когда это лучше сырых строк?
- Если строка содержит много кавычек или хешей, которые мешают использованию
r#"..."#. - Если вы хотите явно контролировать, где именно вставляются переносы строк.
- Для коротких многострочных фрагментов, где читаемость важнее гибкости.
Однако для большинства случаев (SQL, JSON, HTML) сырые строки с хешами остаются более идиоматичным выбором.