I'm having a hard time figuring out how string syntax works in Rust. Specifically, I'm trying to figure out how to make a multiple line string.
- 2Possible duplicate of How do I write a multi-line string in Rust?Jo Liss– Jo Liss2017-02-27 13:48:16 +00:00Commented Feb 27, 2017 at 13:48
- 1It's a bit weird that the older question is marked as a duplicate of a newer one. Shouldn't this be the other way around?Nikita Fedyashev– Nikita Fedyashev2022-08-27 21:59:33 +00:00Commented Aug 27, 2022 at 21:59
- 1@BinaryButterfly I think it's because this question has gotten much more attention and has clearer answersTheTechRobo– TheTechRobo2023-03-17 13:07:17 +00:00Commented Mar 17, 2023 at 13:07
7 Answers
All string literals can be broken across several lines; for example:
let string = "line one line two"; is a two line string, the same as "line one\nline two" (of course one can use the \n newline escape directly too). If you wish to just break a string across multiple lines for formatting reasons you can escape the newline and leading whitespace with a \; for example:
let string = "one line \ written over \ several"; is the same as "one line written over several".
If you want linebreaks in the string you can add them before the \:
let string = "multiple\n\ lines\n\ with\n\ indentation"; It's the same as "multiple\nlines\nwith\nindentation";
5 Comments
concat!() macro to complete the given options (doc.rust-lang.org/std/macro.concat.html)In case you want to do something a bit longer, which may or may not include quotes, backslashes, etc., use the raw string literal notation:
let shader = r#" #version 330 in vec4 v_color; out vec4 color; void main() { color = v_color; }; "#; Outputs:
#version 330 in vec4 v_color; out vec4 color; void main() { color = v_color; }; If you have sequences of double quotes and hash symbols within your string, you can denote an arbitrary number of hashes as a delimiter:
let crazy_raw_string = r###" My fingers #" can#"#t stop "#"" hitting hash##"# "###; Which outputs:
My fingers #" can#"#t stop "#"" hitting hash##"# 8 Comments
Huon's answer is correct but if the indentation bothers you, consider using Indoc which is a procedural macro for indented multi-line strings. It stands for "indented document." It provides a macro called indoc!() that takes a multiline string literal and un-indents it so the leftmost non-space character is in the first column.
let s = indoc! {" line one line two "}; The result is "line one\nline two\n".
Whitespace is preserved relative to the leftmost non-space character in the document, so the following has line two indented 3 spaces relative to line one:
let s = indoc! {" line one line two "}; The result is "line one\n line two\n".
3 Comments
If you want to have fine granular control over spaces in multiline strings with linebreaks without using an external crate you can do the follwing. Example taken from my own project.
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) } } Results in
OCPRecData { msg: Some("Hello World") device_name: None parent_device_name: None } \n\at each code line end creates a line break at the proper position and discards further spaces in this line of code\x20(hex; 32 in decimal) is an ASCII space and an indicator for the first space to be preserved in this line of the string\x20\x20\x20\x20and\x20have the same effect
1 Comment
f.debug_struct() would be a better option.In case you want to indent multiline text in your code:
let s = "first line\n\ second line\n\ third line"; println!("Multiline text goes next:\n{}", s); The result will be the following:
Multiline text goes next: first line second line third line 4 Comments
\n newline escape [...] you can escape the newline and leading whitespace with a {backslash}. (it's very hard to type a backslash in code in a comment, it appears.)with the concat macro
let sql = concat!( "CREATE TABLE test (\n", " id INTEGER,\n", " name TEXT\n", ");\n", ); Comments
When the goal is to write multiline strings for tests, it can sometimes be useful to split the text into lines first:
fn yaml() -> String { "list:\n - item 1\n - item 2".to_string() } fn main() { println!("{}", yaml()); } #[test] fn test_yaml() { let text = yaml(); let lines = text.split('\n').collect::<Vec<&str>>(); assert_eq!(lines[0], "list:"); assert_eq!(lines[1], " - item 1"); assert_eq!(lines[2], " - item 2"); }