skip to content

In Dart, how do string interpolation, raw strings and multi-line strings work, and when is an interpolated string a compile-time constant?

level: juniorimportance: should knowfreq 48%

answer

  1. $name versus ${expression}
  2. interpolation calls toString()
  3. r prefix disables escapes and $
  4. triple quotes span lines
  5. const needs const primitives inside

basics

~20 s

Dart interpolates $name or ${expression} into a string by calling toString(). A raw string (r'...') treats backslashes and $ literally, triple quotes create multi-line strings, and an interpolated string is const only if every interpolated value is a constant null, number, string or bool.

solid answer

~50 s

Single or double quotes both create a `String`. **Interpolation** inserts a value with `$name` for a plain identifier or `${expression}` for anything else, calling the object's `toString()`. The braces matter: `'$item.name'` interpolates `item` and then the literal text `.name`, while `'${item.name}'` reads the property. A **raw string**, prefixed with `r`, treats every character literally, so `r'\d+ $price'` contains a backslash and a dollar sign, which is why regular expressions use raw strings. **Triple quotes** (`'''` or `"""`) create multi-line strings. Adjacent literals are concatenated, even across lines, and `+` works too. A string literal is a **compile-time constant** only if every interpolated expression is a constant evaluating to `null`, a number, a string or a boolean; interpolating a variable or a const list makes it non-const. The recommended lints prefer interpolation over `+` and drop unnecessary braces.

code

dart · 19 lines
dart
class MenuItem {
  final String name;
  final int priceCents;
  const MenuItem(this.name, this.priceCents);
}

const currency = 'EUR';
const header = 'Prices in $currency'; // const: interpolates a const String

void main() {
  const item = MenuItem('Soup', 650);
  print('${item.name}: ${(item.priceCents / 100).toStringAsFixed(2)} $currency');
  print('$item.name'); // bug: prints Instance of 'MenuItem'.name
  print(r'Raw: \n and $currency stay literal');
  const footer = '''
Thank you!
Prices include tax.''';
  print('$header\n$footer');
}

go deeper

for a junior

Recall $name versus ${expression}, the r prefix for raw strings, and triple quotes for multi-line text.

for a middle

Explain the brace bug with property access, why regexes use raw strings, and the rule for const interpolated strings.

for a senior

Keep string-building readable and correct in reviews, using the recommended lints and StringBuffer for heavy concatenation.

for a principal

Decide where user-visible strings live, in code, constants or localization files, so interpolation stays safe to translate.

## Quotes and escapes Dart has one string type, `String`, and several literal forms. Single and double quotes are interchangeable; pick the one that avoids escaping: ```dart var a = 'It\'s escaped'; var b = "It's easier with the other delimiter"; ``` The usual escapes apply: `\n`, `\t`, `\\`, `\'`, `\$`, `\uXXXX` and `\u{...}`. ## Interpolation Interpolation embeds values: - **`$identifier`** for a simple name: `'Total: $total'`. - **`${expression}`** for anything else: `'${item.name} x${item.quantity}'`, `'${cents ~/ 100}'`. - Dart calls **`toString()`** on the result, so any object can be interpolated. The classic bug is forgetting braces around a property access. `'$item.name'` interpolates `item.toString()` followed by the literal `.name`, printing something like `Instance of 'MenuItem'.name`. The recommended lint `unnecessary_brace_in_string_interps` flags braces only where they are not needed, so following it never introduces this bug. ## Concatenation 1. **Adjacent literals** are joined at compile time: `'Margherita ' 'with basil'`, even across line breaks. The `prefer_adjacent_string_concatenation` lint prefers this over `+` between literals. 2. **`+`** joins any two strings at runtime. 3. **Interpolation** is preferred for mixing values and text; `prefer_interpolation_to_compose_strings` flags `'Total: ' + total.toString()`. For building long strings in loops, `StringBuffer` is the tool, which belongs with the core library. ## Multi-line strings Triple quotes, `'''` or `"""`, let a literal span lines, keeping the line breaks: ```dart const receiptFooter = ''' Thank you! Prices include tax.'''; ``` Interpolation and escapes work inside them as usual. ## Raw strings An `r` prefix makes a **raw string**: backslashes are not escapes, and `$` is not interpolation. dart.dev: "In a raw string, not even `\n` gets special treatment." The SDK's `RegExp` documentation recommends raw strings so that each character, "including `\` and `$`", is taken literally: ```dart final pricePattern = RegExp(r'^\$?(\d+)\.(\d{2})$'); ``` Without `r`, every backslash would have to be doubled and every `$` escaped. ## When a string is const String literals are compile-time constants **as long as every interpolated expression is a compile-time constant that evaluates to `null`, a number, a string or a boolean**: | Interpolated value | Const string? | |---|---| | `const currency = 'EUR'` | Yes | | `const taxPercent = 7` | Yes | | `var name = 'Soup'` | No: not a constant | | `const sizes = ['S', 'M']` | No: a list is not a primitive | This matters in constant contexts such as `const` declarations, annotations and default parameter values. ## Common mistakes 1. Forgetting braces around property access or method calls: `'$item.name'`, `'$price.toStringAsFixed(2)'`. 2. Expecting a raw string to interpolate: `r'Total: $total'` prints the dollar sign and the name. 3. Building text with `+` and `toString()` everywhere instead of one interpolated literal. 4. Declaring a string `const` while interpolating a variable, which fails with a constant-value error. 5. Relying on a double's default `toString()` for prices, which differs between native and web builds; format explicitly instead. ## Style notes - Prefer interpolation over concatenation for mixed text and values. - Drop braces for simple identifiers, keep them for everything else. - Use raw strings for regular expressions and Windows-style paths, where backslashes are common. ## Equality Two strings are `==` when they contain the same sequence of code units, regardless of how they were built; interpolated and concatenated strings compare by content, not identity.

  • Why do Dart regular expressions usually use raw strings?
    Regex syntax is full of backslashes and often `$`. In a normal string each backslash must be doubled and each `$` escaped, or it starts interpolation. A raw string, `r'...'`, takes both literally, which the SDK's `RegExp` docs recommend.
  • Can you interpolate a const list into a const Dart string?
    No. A const string may interpolate only constants that evaluate to `null`, a number, a string or a boolean. A const list is a constant but not one of those primitives, so the string is not a compile-time constant.

saying these in an interview costs you the question

  • '$item.name' reads the name property of item
  • Raw strings still interpolate $variables
  • Any string containing interpolation can be declared const
  • Adjacent string literals need a + between them
  • Interpolation requires the value to already be a String