Question

Rust Multiline String Literals: Syntax, Raw Strings, and Line Breaks

ruststringsyntax

Question

I am learning how string syntax works in Rust, and I want to understand how to create a multiline string. Specifically, what is the correct syntax for a string literal that spans multiple lines in Rust?

Short Answer

By the end of this page, you will understand how multiline string literals work in Rust, how line breaks are preserved, when to use normal string literals versus raw string literals, and how to avoid common mistakes when writing multi-line text.

Concept

In Rust, a string literal can span multiple lines simply by writing the text across lines between double quotes. The newline characters become part of the string.

Rust also supports raw string literals, which are useful when you want to include characters like backslashes (\) or quotes without escaping them.

Why this matters

Multiline strings are useful when you need to store:

  • formatted messages
  • SQL queries
  • JSON samples
  • file templates
  • usage text for command-line tools

Understanding how Rust treats line breaks and indentation helps you produce the exact string you expect.

Basic idea

A normal multiline string literal looks like this:

let text = "Hello
Rust";

That string contains a newline between Hello and Rust.

You can also write it visually across lines:

let text = "Hello
Rust";

or more commonly:

let text = "Hello
Rust";

In Rust source code, if you physically put the string on separate lines inside the quotes, those line breaks are included in the string.

Raw strings

A raw string starts with r before the quotes:

let text = r"Line 1
Line 2";

In this case, \n is treated as the two characters \ and n, not as a newline.

If you want actual line breaks in a raw string, write actual line breaks:

let text = r"Line 1
Line 2";

or:

let text = r"Line 1
Line 2";

The key rule is:

  • Normal strings interpret escapes like \n
  • Raw strings do not interpret escapes

Indentation matters

If you indent a multiline string in your code, those spaces usually become part of the string too. That can surprise beginners.

let text = "first line
    second line";

Here, second line starts with four spaces inside the actual string.

Mental Model

Think of a Rust string literal like text written onto a sheet of paper.

  • If you press Enter, you create a real new line on the paper.
  • If you type \n in a normal string, Rust converts that into pressing Enter for you.
  • If you type \n in a raw string, Rust leaves it exactly as typed.

So:

  • normal string = "interpret special instructions"
  • raw string = "copy text exactly as written"

This is why raw strings are useful for things like file paths, JSON examples, or regular expressions, where lots of backslashes would otherwise be annoying.

Take Quiz

Syntax and Examples

Normal multiline string literal

fn main() {
    let message = "Hello,
Rust!";

    println!("{}", message);
}

This prints:

Hello,
Rust!

The newline between Hello, and Rust! is part of the string.

Using \n in a normal string

fn main() {
    let message = "Hello,\nRust!";
    println!("{}", message);
}

This produces the same result as the previous example.

Raw multiline string literal

fn main() {
    let message = r"Hello,
Rust!";
    println!("{}", message);
}

This also contains a real newline because the string itself spans two lines.

Raw string with literal backslashes

fn main() {
    let message = r"Hello,\nRust!";
    println!("{}", message);
}

This prints:

Hello,\nRust!

Because raw strings do not treat \n as a newline escape.

Raw strings with quotes inside

fn main() {
    let json = r#"{
  "name": "Rust"
}"#;

    println!("{}", json);
}

The r#"..."# form lets you include double quotes inside the string without escaping them.

Step by Step Execution

Consider this example:

fn main() {
    let text = "One
Two";
    println!("{}", text);
}

Step by step

  1. Rust reads the string literal starting at the first ".
  2. It sees One and stores those characters.
  3. It encounters a line break inside the string literal.
  4. That line break becomes a newline character in the string.
  5. Rust reads Two and adds it after the newline.
  6. The string is assigned to text.
  7. println!("{}", text); prints the string exactly as stored.

Stored value

The value inside text is effectively:

One
Two

Output

One
Two

Now compare with this raw string:

fn main() {
    let text = r"One\nTwo";
    println!("{}", text);
}

Step by step here:

  1. Rust sees a raw string literal.
  2. It does not interpret \n as a newline.
  3. The characters \ and n are stored literally.
  4. Printing shows One\nTwo.

Real World Use Cases

Multiline strings appear often in real Rust programs.

Command-line help text

let help = "Usage:
  app run
  app test
  app help";

Useful for CLI tools.

SQL queries

let query = "SELECT id, name
FROM users
WHERE active = true";

This keeps long queries readable.

JSON or config templates

let template = r#"{
  "debug": true,
  "port": 8080
}"#;

Raw strings reduce escaping.

Email or log messages

let message = "Build finished.
No errors found.
Ready to deploy.";

Useful when formatting human-readable output.

Test data

let input = "apple
banana
orange";

Helpful in unit tests where exact line structure matters.

Take Quiz

Real Codebase Usage

In real Rust codebases, developers often choose between normal and raw strings based on what makes the text easiest to read and maintain.

Common patterns

Readable templates

Developers use multiline strings for templates, sample payloads, and embedded documentation.

let request_body = r#"{
  "username": "alice",
  "active": true
}"#;

Keeping SQL readable

let sql = "SELECT id, email
FROM customers
WHERE subscribed = true";

Exact matching in tests

Tests often compare exact multiline output.

let expected = "line one
line two";
assert_eq!(expected, actual_output);

Validation and error messages

Programs sometimes build user-facing multiline messages for validation errors.

let error_message = "Invalid configuration:
- missing host
- missing port";

Practical advice

  • Use normal strings when you want escape sequences like \n or \t
  • Use raw strings when escaping would make the text hard to read
  • Watch indentation carefully when exact output matters
  • In tests, compare exact strings so hidden spaces and line breaks are caught early

Common Mistakes

1. Expecting raw strings to process \n

Broken example:

fn main() {
    let text = r"Hello\nRust";
    println!("{}", text);
}

This prints:

Hello\nRust

If you want a newline, use a normal string:

let text = "Hello\nRust";

or write an actual newline inside the raw string.

2. Forgetting indentation becomes part of the string

Broken example:

fn main() {
    let text = "first line
        second line";
    println!("{}", text);
}

The spaces before second line are included.

Avoid this by aligning the text intentionally.

3. Escaping quotes unnecessarily in raw strings

Unnecessary escaping:

let text = r"She said \"hi\"";

Cleaner version:

let text = r#"She said "hi""#;

4. Confusing source formatting with string content

Beginners sometimes think line breaks in code are only visual. In string literals, they usually become real characters in the string.

5. Comparing strings without noticing hidden whitespace

let a = "hello
world";
let b = "hello
    world";
assert_eq!(a, b); // fails

Use debug output when checking exact contents:

println!("{:?}", a);
println!("{:?}", b);

Comparisons

ConceptSyntaxEscapes processed?Best use
Normal string literal"Hello\nRust"YesGeneral strings with escapes
Multiline normal string`"Hello
Rust"`YesText with real line breaks
Raw string literalr"Hello\nRust"NoText with many backslashes
Raw string with #r#"say "hi""#NoText containing quotes

Normal string vs raw string

  • Normal string

    • supports \n, \t, \", and other escapes
    • better when you need special characters through escape sequences
  • Raw string

    • treats most content literally
    • better when the text contains many backslashes or quotes

Actual newline vs \n

FormMeaning
"Hello\nRust"newline created by escape sequence
`"Hello
Rust"`newline created by writing the string across lines
r"Hello\nRust"literal backslash and n
`r"Hello
Rust"`actual newline in a raw string
Take Quiz

Cheat Sheet

Quick reference

Normal string

let s = "Hello\nRust";
  • \n becomes a newline
  • escapes are processed

Multiline normal string

let s = "Hello
Rust";
  • actual line break is stored in the string

Raw string

let s = r"Hello\nRust";
  • \n stays as two characters
  • escapes are not processed

Multiline raw string

let s = r"Hello
Rust";
  • actual line break is stored
  • backslashes stay literal

Raw string with quotes inside

let s = r#"He said "hello""#;

Rules to remember

  • Line breaks inside the quotes become part of the string
  • Indentation inside the quotes also becomes part of the string
  • Use normal strings for escapes like \n
  • Use raw strings to avoid heavy escaping
  • Use r#"..."# if the string contains quotes

Debug exact contents

println!("{:?}", s);

This helps reveal hidden \n and spaces.

FAQ

How do I write a multiline string in Rust?

You can place the text on multiple lines inside a string literal. The line breaks become part of the string.

Does Rust preserve newlines in a multiline string?

Yes. If the string literal spans lines, those newlines are included in the final value.

What is the difference between a normal string and a raw string in Rust?

A normal string processes escapes like \n. A raw string treats content literally, so \n stays as \n.

How do I include quotes inside a Rust raw string?

Use hashes, such as r#"quoted text"#, so inner double quotes do not end the string.

Why does my multiline string contain extra spaces?

Because indentation inside the quotes is usually part of the string. Align the text carefully.

Should I use \n or actual line breaks?

Use whichever makes the code clearer. \n is useful for short strings; actual line breaks are often easier to read for longer text.

Are multiline string literals and String the same thing in Rust?

No. A string literal has type &str. You can convert it to String if needed, for example with to_string() or String::from(...).

Take Quiz

Mini Project

Description

Build a small Rust program that prints a formatted command-line help message using multiline string literals. This demonstrates how real line breaks are stored, when raw strings are useful, and how formatting affects output.

Goal

Create a Rust program that stores and prints a readable multiline help message and a JSON example.

Requirements

  1. Create a normal multiline string literal for a help message.
  2. Print the help message exactly as written.
  3. Create a raw string literal containing a JSON example.
  4. Print the JSON example without extra escaping.
Take Quiz

Keep learning

Related questions

View more