419

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.

3
  • 2
    Possible duplicate of How do I write a multi-line string in Rust? Commented Feb 27, 2017 at 13:48
  • 1
    It'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? Commented Aug 27, 2022 at 21:59
  • 1
    @BinaryButterfly I think it's because this question has gotten much more attention and has clearer answers Commented Mar 17, 2023 at 13:07

7 Answers 7

524

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";

Sign up to request clarification or add additional context in comments.

5 Comments

If only readability is the issue, I would like to add the concat!() macro to complete the given options (doc.rust-lang.org/std/macro.concat.html)
What if I want to keep the space on the next line instead of before the backslash on the previous one? Is that possible or will it always be "eaten" because it's considered part of the indentation?
@theberzi, yes, the only way to keep whitespace is to place it before the \\ as all leading whitespace is eaten on the next line.
It looks like the trailing backslash only removes leading space characters on the next line, not all whitespace up to the first character (for instance, if you indent with tabs, they won't be removed).
@BallpointBen This has apparently been fixed, my tabs are getting eaten just fine with rustc 1.77.
311

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; }; 

Playground link


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

But... you only need to escape newlines if you don't want newlines in the result, and raw strings don't help with that.
Raw strings just prevent you from having to add a '\' at the end of every line if you don't care about the newlines (such as when you are embedding code which is newline agnostic like shaders and kernels) or, as you alluded to, when the newlines are actually necessary. It just makes it easier to embed code which you might want to edit and not have to hassle with the '\' at the end of each line. That's all.
If you want (or don't mind) newlines in the resulting string, plain double quoted strings will do perfectly well, as shown in the other examples. If you want to avoid newlines, raw strings are no good. They really only help if the text includes quotes, backslashes, etc - as may happen in embedded source.
I see what you're getting at now and you're absolutely right.
It would help to show the output of printing these strings. From the answer itself I can't tell what will happen with newlines, and how indentation is handled.
|
139

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

Ah! Thanks so much for this! I was about to create my own question, specifically about the best way to do a multiline string literal with indentation, that also that preserved code-indentation nicely, when I stumbled across your answer here! For reference, I created a rust playground which lists various options I came up with, and their relative shortcomings: play.rust-lang.org/…
This exact problem bugs me in pretty much every language I ever use, and there's always some different way around it. Gotta love being able to use such a friendly macro! TY.
if you need string interpolation, see indoc::formatdoc!
26

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\x20 and \x20 have the same effect

1 Comment

I'd like to note that in this specific example provided by me, f.debug_struct() would be a better option.
14

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

Please explicitly state, using prose, what piece of the code is important to this behavior.
Right now, this appears to not add anything new to the accepted answer, which states: one can use the \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.)
This comment is suggesting a way to combine the two points in the accepted answer: how you can produce a multi-line string, written as multiples lines in code, but that at the same time is allowed to —for stylistic or legibility reason— get its own indentation in code, without this indentation ending in the final string. It’s not made very clear in the text, but it’s a common use case and thus a valuable suggestion imho. (See the answer by dtolnay for the crate version of this.)
Re: Dato's comment: "See the answer by dtolnay for the crate version of this": to be clear, Indoc is different that the example given here, since indoc! preserves indentation.
1

with the concat macro

let sql = concat!( "CREATE TABLE test (\n", " id INTEGER,\n", " name TEXT\n", ");\n", ); 

Comments

0

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"); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.