Каков синтаксис многострочного строкового литерала?

Ответы:

173

Все строковые литералы можно разбить на несколько строк; например:

let string = "line one
line two";

- это двухстрочная строка, такая же, как "line one\nline two"(конечно, можно \nнапрямую использовать переход с новой строки). Если вы хотите просто разбить строку на несколько строк по причинам форматирования, вы можете экранировать новую строку и начальные пробелы с помощью \; например:

let string = "one line \
    written over \
    several";

такое же, как "one line written over several".

Если вам нужны разрывы строк в строке, вы можете добавить их перед \:

let string = "multiple\n\
              lines\n\
              with\n\
              indentation";

Это то же самое, что и "multiple\nlines\nwith\nindentation";

Юон
источник
2
Если проблема только в удобочитаемости, я хотел бы добавить concat!()макрос для завершения заданных параметров ( doc.rust-lang.org/std/macro.concat.html )
hakononakani
84

Если вы хотите сделать что-то более длинное, что может включать или не включать кавычки, обратную косую черту и т. Д., Используйте буквальную нотацию необработанной строки :

let shader = r#"
    #version 330

    in vec4 v_color;
    out vec4 color;

    void main() {
        color = v_color;
    };
"#;

Если у вас есть последовательности двойных кавычек и хеш-символов в вашей строке, вы можете обозначить произвольное количество хэшей в качестве разделителя:

let crazy_raw_string = r###"
    My fingers #"
    can#"#t stop "#"" hitting
    hash##"#
"###;
c0g
источник
Но ... вам нужно избегать символов новой строки только в том случае, если вы не хотите видеть новую строку в результате, а необработанные строки в этом не помогают.
poolie 04
Необработанные строки просто избавляют вас от необходимости добавлять '\' в конце каждой строки, если вы не заботитесь о новых строках (например, когда вы встраиваете код, который не зависит от новой строки, например, шейдеры и ядра) или, как вы упомянули до, когда переводы строки действительно необходимы. Это просто упрощает встраивание кода, который вы, возможно, захотите отредактировать, и избавляет от необходимости возиться с символом '\' в конце каждой строки. Вот и все.
c0g 07
1
Если вы хотите (или не против) новой строки в результирующей строке, подойдут простые строки с двойными кавычками, как показано в других примерах. Если вы хотите избежать перевода строки, необработанные строки никуда не годятся. Они действительно помогают только в том случае, если текст содержит кавычки, обратную косую черту и т. Д., Что может случиться во встроенном источнике.
poolie 08
2
Я понимаю, к чему вы клоните, и вы абсолютно правы.
c0g
1
Это помогло бы показать результат печати этих строк. Из самого ответа я не могу сказать, что произойдет с символами новой строки и как обрабатываются отступы.
bluenote10
48

Ответ Хьюона правильный, но если отступы вас беспокоят , подумайте об использовании Indoc, который является процедурным макросом для многострочных строк с отступом. Это означает «документ с отступом». Он предоставляет вызываемый макрос, indoc!()который принимает многострочный строковый литерал и отменяет отступы, так что крайний левый непробельный символ находится в первом столбце.

let s = indoc! {"
    line one
    line two
"};

Результат есть "line one\nline two\n".

Пробелы сохраняются относительно крайнего левого непробельного символа в документе, поэтому следующая строка имеет отступ на 3 пробела относительно первой строки:

let s = indoc! {"
    line one
       line two
"};

Результат есть "line one\n line two\n".

dtolnay
источник
8

Если вы хотите сделать отступ в многострочном тексте в коде:

let s = "first line\n\
    second line\n\
    third line";

println!("Multiline text goes next:\n{}", s);

Результат будет следующий:

Multiline text goes next:
first line
second line
third line
Игорь
источник
Пожалуйста, четко укажите, используя прозу, какой фрагмент кода важен для такого поведения.
Shepmaster
Прямо сейчас это, похоже, не добавляет ничего нового к принятому ответу , в котором говорится: можно использовать \nescape-символ новой строки [...] вы можете экранировать новую строку и ведущие пробелы с помощью a{backslash} . (похоже, очень сложно ввести обратную косую черту в код в комментарии.)
Shepmaster
2
Этот комментарий предлагает способ объединить два момента в принятом ответе: как вы можете создать многострочную строку, записанную в виде нескольких строк в коде, но в то же время разрешено - по стилистическим причинам или соображениям разборчивости - получить собственный отступ в коде, без этого отступа, заканчивающегося последней строкой. Это не очень ясно сказано в тексте, но это общий вариант использования и, следовательно, ценное предложение, imho. (См. Ответ dtolnay для версии с ящиком.)
Dato
0

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

impl Display for OCPRecData {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "OCPRecData {{\n\
            \x20   msg: {:?}\n\
            \x20   device_name: {:?}\n\
            \x20   parent_device_name: {:?}\n\
        }}", self.msg, self.device_name, self.parent_device_name)
    }
}

Результаты в

OCPRecData {
    msg: Some("Hello World")
    device_name: None
    parent_device_name: None
}
  • \n\ в конце каждой строки кода создает разрыв строки в нужной позиции и отбрасывает дальнейшие пробелы в этой строке кода
  • \x20 (шестнадцатеричный; 32 в десятичном) - это пробел ASCII и индикатор сохранения первого пробела в этой строке строки.
  • \x20\x20\x20\x20и \x20 иметь такой же эффект
phip1611
источник