String Literals
A complete guide to string literals in Go, covering interpreted and raw forms, escape sequences, and common mistakes
A string literal is a fixed sequence of characters you write directly in Go source code to represent a string value. Go has two distinct forms: interpreted literals enclosed in double quotes, and raw literals enclosed in backticks. Understanding the differences between them is essential for writing correct, readable code.
Interpreted String Literals
Double-quoted strings are the default form you will see most often. They are called interpreted because the Go compiler processes escape sequences inside them.
greeting := "Hello, Gophers!"
This literal can contain any Unicode character except a newline or an unescaped double quote. To include a double quote, a backslash, or control characters, you use an escape sequence—a backslash followed by a specific character.
quote := "She said \"Go is fantastic!\""
path := "C:\\Users\\gopher\\docs"
Every \ in an interpreted literal has special meaning. If you need a literal backslash, you must write \\. For a newline, you write \n; for a tab, \t. The table later in this section covers all recognized sequences.
Unescaped double quotes break compilation:
If you put an unescaped " inside an interpreted literal, the compiler sees it as the end of the string. The code "She said "hello"" causes a syntax error. Always use \" for a double quote inside a double-quoted string.
Escape sequences are resolved at compile time. The string stored at runtime already contains the actual bytes for the newline, tab, or quote you specified. This means there is no performance penalty for using them—they are no different from writing the corresponding raw bytes.
Raw String Literals
A raw string literal is a sequence of characters between backticks (`). No escape processing takes place: what you see is exactly what you get.
raw := `Line one
Line two
Indented line
Literal backslash \ and quote " are ordinary here`
Because there is no escape processing, you can safely write backslashes, double quotes, and newlines without any extra syntax. This makes raw strings the natural choice for regular expressions, file paths on Windows, JSON snippets embedded in code, and multi-line text blocks.
Carriage returns are stripped:
The Go specification mandates that carriage return characters (\r) inside a raw string literal are silently discarded. This means you can copy text with Windows-style line endings (\r\n) into a raw string and only the newlines will remain.
The one character you cannot include in a raw string literal is a backtick itself—it would end the literal. If you must embed a backtick, you will need to use an interpreted literal and escape it, or concatenate with a backtick-bearing interpreted string.
// Correct: using concatenation to include a backtick in output
output := "This is a backtick: `" + "`" + ` is included`
Raw strings keep all indentation:
When you write a raw string that spans multiple lines, every space and tab from the source file is preserved exactly as it appears. Indenting the closing backtick to align with surrounding code will insert that whitespace into the string value, often unexpectedly. Always place the closing backtick at column 1 if you want no leading whitespace on subsequent lines.
Escape Sequences in Interpreted Strings
The following escape sequences are recognized inside double-quoted string literals. Any backslash not followed by one of these characters is illegal.
| Sequence | Meaning |
|---|---|
\a | Alert or bell (U+0007) |
\b | Backspace (U+0008) |
\f | Form feed (U+000C) |
\n | Newline (U+000A) |
\r | Carriage return (U+000D) |
\t | Horizontal tab (U+0009) |
\v | Vertical tab (U+000B) |
\\ | Backslash (U+005C) |
\' | Single quote (U+0027) |
\" | Double quote (U+0022) |
\xNN | Byte value as two hex digits |
\uNNNN | Unicode code point (4 hex) |
\UNNNNNNNN | Unicode code point (8 hex) |
For Unicode escapes, the four- and eight-digit forms denote the same code point; the eight-digit form is useful for supplementary characters beyond U+FFFF.
heart := "I \u2665 Go" // I ♥ Go
smile := "\U0001F600" // 😀
Each escape represents a single character in the string, even though it spans several source characters.
Readable regex without double escaping:
A raw string is the idiomatic way to write a regular expression in Go. Compare:
// Interpreted: painful double escaping
re := regexp.MustCompile("\\d{3}-\\d{2}-\\d{4}")
// Raw: write the pattern as you would in a regex tester
re := regexp.MustCompile(`\d{3}-\d{2}-\d{4}`)
Using backticks avoids the need to think about which backslashes are for Go and which are for the regex engine.
Interpreted vs Raw: Choosing the Right Form
Interpreted ("...") | Raw (`...`) |
|---|---|
| Supports escape sequences | No escape processing |
Must escape " and \ | Cannot contain backtick character |
Single line only (newlines must be \n) | Multiline: newlines are literal |
| Ideal for most strings, especially with control chars | Ideal for regex, paths, JSON, SQL, templates |
Neither form is a “smarter” default—each solves a different readability problem. Use interpreted strings when escape sequences are part of the value. Use raw strings when backslashes and newlines are part of the content and escaping them would harm readability.
String Literals Are Constants
A string literal is a constant expression. Its value is known at compile time, and the compiler can use it anywhere a constant string is required—for example, in const declarations or in switch case labels.
const welcome = "Hello"
const rawBlock = `
=====================
= WELCOME TO GO =
=====================
`
Because the literal is a constant, it cannot be assigned to at runtime. The underlying bytes are immutable. This leads directly to the next point.
Taking the Address of a String Literal
You cannot write &"hello" in Go. This is not an oversight—it follows from the fact that a string literal is a constant, not an addressable variable.
Compile error: cannot take address of string literal:
The expression p := &"hello" will not compile. The Go specification forbids taking the address of any constant, and string literals are constants. You must first assign the literal to a variable and then take its address.
s := "hello"
p := &s // allowed
The restriction protects the immutability contract. If &"hello" were allowed, a function that modifies the string through the pointer could change what is conceptually a fixed value. Other constants like 42 or 3.14 likewise cannot have their addresses taken. Composite literals like &MyStruct{...} work because they are not constants—they allocate a new value at runtime.
This design choice is consistent with Go’s systems-language philosophy: constants are truly constant, and addressability implies mutability. If you need a pointer to a string, create a variable first.
Common Mistakes and How to Avoid Them
Forgetting to escape a backslash in interpreted strings.
If you mean a literal backslash inside a double-quoted string, write \\. A single \ followed by an unrecognised character is a compile error.
// Wrong: path := "C:\new\folder"
path := "C:\\new\\folder" // correct
Trying to put a backtick inside a raw string.
The backtick is the delimiter; you cannot escape it. Use concatenation if you need a backtick in the value.
Indenting a raw string’s closing backtick.
Every space before the closing backtick is part of the string. If you want clean multi-line output, do not indent the closing backtick.
// Surprise: leading spaces and tabs are embedded
msg := `
This starts with a newline and four spaces
`
// Cleaner: start and end at column 1
msg := `This starts right away
and the next line is flush.`
Confusing \x escapes with UTF-8 multibyte sequences.
\x specifies a single byte, not a Unicode code point. For characters beyond ASCII, use \u or \U escapes to avoid breaking multi-byte UTF-8 sequences.
Using \x for code points above 0x7F:
s := "\xE2\x82\xAC" // UTF-8 bytes for € – works but fragile
s := "\u20AC" // clear and self-documenting
Stick to \u and \U for Unicode characters to keep intent explicit.
Expecting raw strings to trim indentation.
Raw strings include exactly the characters between the backticks. If you want automatically trimmed multi-line strings, you must handle that yourself or use a helper function. The standard library does not strip indentation from raw literals.
Summary
Interpreted and raw string literals are two tools for expressing string constants in Go. Interpreted literals give you fine-grained control over special characters through escape sequences; raw literals let you write text exactly as it should appear, free from backslash noise. The choice hinges on whether the value contains more characters that need escaping (like backslashes and newlines) or characters that must not be escaped (like the backtick).
The most important structural fact to remember is that string literals are constants: they are immutable, known at compile time, and not addressable. This keeps programs safe and predictable, even though it sometimes means you must assign a literal to a variable before taking its address.