Avatar ·

Как задать многострочную строковую константу в Rust? Синтаксис и примеры

Всем привет! Я только начал изучать Rust и столкнулся с проблемой. Мне нужно объявить строковую переменную, которая содержит несколько строк текста. В других языках, например, в Python, я могу просто написать: ```python text = """Это многострочная строка""" ``` Но в Rust я пробую так: ```rust let text = "Это многострочная строка"; ``` И компилятор выдаёт ошибку: `error: unterminated double quote string`. Я также пробовал экранировать символы переноса строки с помощью `\n`, но это неудобно для больших текстов, например, для JSON, SQL-запроса или длинного сообщения. Подскажите, пожалуйста, какой правильный синтаксис для многострочных строковых литералов в Rust? Есть ли какие-то особенности, например, с отступами или пробелами? Заранее спасибо! <<>>

Использование сырых строковых литералов (raw string literals)

В Rust для создания многострочных строковых констант используется синтаксис сырых строк (raw strings). Он позволяет включать переносы строк и любые другие символы без экранирования. Основной синтаксис — r#"..."#.

let text = r#"Это
многострочная
строка"#;

println!("{}", text);
// Вывод:
// Это
// многострочная
// строка

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

let text = r##"Строка с кавычками: "вот так" и решёткой: #"##;

println!("{}", text);
// Строка с кавычками: "вот так" и решёткой: #

Важные нюансы

  • Отступы: Сырые строки сохраняют все пробелы и табуляции, включая отступы кода. Если вы пишете многострочную строку внутри функции с отступом, она будет включать эти пробелы. Чтобы избежать этого, можно использовать trim_matches или выравнивать строку по левому краю.
  • Экранирование: В сырых строках \n не работает как перенос — это будет просто литерал обратной косой черты и буквы n. Если нужны escape-последовательности, используйте обычные строки с \n.
  • Производительность: Строковые литералы всегда создаются во время компиляции и размещаются в статической памяти. Это безопасно и эффективно.

Альтернатива: обычные строки с переносами

Если вам нужно использовать escape-последовательности (например, \n, \t), можно объединять строки через конкатенацию или использовать макрос concat!:

let text = "Это\nмногострочная\nстрока";
// Работает, но неудобно для больших блоков

// Или через макрос:
let text = concat!(
    "Это\n",
    "многострочная\n",
    "строка"
);

Пример с JSON

let json = r#"{
    "name": "Rust",
    "version": "1.75",
    "features": ["безопасность", "скорость"]
}"#;

// Парсинг (требуется crate serde_json)
let parsed: serde_json::Value = serde_json::from_str(json).unwrap();

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

<<>>

Использование макроса indoc для чистых отступов

Если вы пишете многострочную строку внутри функции и хотите сохранить читаемость кода без лишних пробелов, рекомендую крейт indoc. Он автоматически удаляет отступы, соответствующие первому символу строки.

use indoc::indoc;

fn main() {
    let text = indoc! {"
        Это
        многострочная
        строка
    "};
    // Результат: "Это\nмногострочная\nстрока"
    // Никаких пробелов слева!
}

Добавьте в Cargo.toml: indoc = "2.0". Это особенно удобно для встраивания SQL-запросов, HTML-шаблонов или тестовых данных.

Когда это нужно?

  • Код с глубокой вложенностью (например, внутри impl-блоков).
  • Длинные строки, которые должны быть выровнены по левому краю.
  • Совместная работа с сырыми строками: indoc!(r#"..."#).