After the input steps on the File structure page, the compiler splits the characters into white space, comments and tokens. Tokens are keywords, identifiers, literals, lifetimes, punctuation and delimiters (Reference: Lexical structure). Some details depend on the crate’s edition, and these are marked.
White space
White space separates tokens and is otherwise ignored. It is the characters of the
Unicode Pattern_White_Space set: horizontal tab (U+0009),
line feed (U+000A), vertical tab (U+000B), form feed
(U+000C), carriage return (U+000D), space
(U+0020), next line (U+0085), the left-to-right and
right-to-left marks (U+200E, U+200F), and the line and
paragraph separators (U+2028, U+2029).
Comments and doc comments
| Form | Kind | Equivalent to |
|---|---|---|
// text | Line comment | White space |
/* text */ | Block comment; may span lines and nests | White space |
/// text | Outer line doc comment, exactly three slashes | #[doc = " text"] |
/** text */ | Outer block doc comment, exactly two asterisks | #[doc = " text "] |
//! text | Inner line doc comment | #![doc = " text"] |
/*! text */ | Inner block doc comment | #![doc = " text "] |
- Block comments nest, so a block can comment out code that has blocks in it. Block doc comments nest the same way.
- Four or more slashes (
////), three or more asterisks (/***) and the empty block/**/are ordinary comments, not doc comments.//!!and/*!!are inner doc comments; the second!is part of the text. - An outer doc comment documents the item, or other form that takes an outer attribute, that follows it. One with nothing to attach to is an error. An inner doc comment documents the enclosing item, usually a module.
- A block doc comment ends at the first
*/, even inside Markdown back ticks. Line doc comments do not have this limit. - A bare carriage return is not allowed in a doc comment.
- The
rustdoctool reads doc comments as Markdown and builds pages from them.
//! Crate-level documentation, because this is at the start of the root file.
/// Adds one to a number.
///
/// # Examples
///
/// ```
/// assert_eq!(add_one(1), 2);
/// ```
pub fn add_one(x: i32) -> i32 { x + 1 }
/* A block comment /* with a nested comment */ inside it. */
Identifiers
IDENTIFIER_OR_KEYWORD: ( XID_Start | _ ) XID_Continue*
RAW_IDENTIFIER: r# IDENTIFIER_OR_KEYWORD
NON_KEYWORD_IDENTIFIER: IDENTIFIER_OR_KEYWORD, except a strict or reserved keyword
IDENTIFIER: NON_KEYWORD_IDENTIFIER | RAW_IDENTIFIER
RESERVED_RAW_IDENTIFIER: r# ( _ | crate | self | Self | super )
- Identifiers follow Unicode Standard Annex 31: an
XID_Startcharacter or_, thenXID_Continuecharacters. Sofoo,_identifier,Москваand東京are all identifiers. The zero-width characters ZWNJ and ZWJ are not allowed. - Identifiers are normalised to NFC. Two identifiers are the same if their NFC forms are equal. Macros receive normalised identifiers.
- A name starting with
_usually marks an intentionally unused identifier and silencesrustc’s unused warning. The single character_is a keyword. - Only ASCII is allowed for
extern cratedeclarations (except the name afteras), external crate names in paths, module names loaded from the file system without apathattribute, items with#[no_mangle]and item names in external blocks.
Raw identifiers
Writing r# before a name lets it be any strict or reserved keyword.
The r# is not part of the name, so r#match and an
identifier named match in another crate’s edition are the same. This
lets code use names that became keywords in a later edition. The five exceptions are
r#_, r#crate, r#self, r#Self and
r#super, which are errors.
fn r#match(needle: &str, haystack: &str) -> bool {
haystack.contains(needle)
}
let r#async = 1; // async is a keyword from edition 2018
let r#gen = 2; // gen is reserved from edition 2024
Keywords
Rust divides its keywords into strict, reserved and weak (Reference: Keywords).
Strict keywords
These cannot be used as names of items, variables, parameters, fields, variants, type or lifetime parameters, labels, macros, attributes, macro placeholders or crates.
| Group | Keywords |
|---|---|
| Items and modules | const crate enum extern fn impl mod pub self Self static struct super trait type use where |
| Control flow | break continue else for if in loop match return while |
| Values and bindings | as false let move mut ref true unsafe _ |
| From edition 2018 | async await dyn |
Reserved keywords
These have the same restrictions as strict keywords but are not used yet.
| Edition | Keywords |
|---|---|
| All | abstract become box do final macro override priv typeof unsized virtual yield |
| From 2018 | try |
| From 2024 | gen |
Weak keywords
These have a special meaning only in certain places and can otherwise be used as names.
| Word | Special meaning |
|---|---|
macro_rules | Defines a macro |
union | Keyword only in a union declaration |
'static | The static lifetime; cannot be used as a generic lifetime parameter or a loop label |
safe | Used for functions and statics in external blocks |
raw | Keyword only in the forms &raw const and &raw mut |
In edition 2015, dyn is weak: it is a keyword only in a type position
where it is followed by a path that does not start with :: or
<, a lifetime, a question mark, a for keyword or an
opening parenthesis. From edition 2018 it is a strict keyword.
Literals
A literal is a single token that gives a constant value. The compiler checks a literal’s suffix when the token is used as an expression or pattern, not when it is read, so a macro can receive a literal with any suffix.
| Literal | Example | Type | Escapes |
|---|---|---|---|
| Character | 'H' | char | Quote, ASCII, Unicode |
| String | "hello" | &'static str | Quote, ASCII, Unicode |
| Raw string | r#"hello"# | &'static str | None |
| Byte | b'H' | u8 | Quote, Byte |
| Byte string | b"hello" | &'static [u8; N] | Quote, Byte |
| Raw byte string | br#"hello"# | &'static [u8; N] | None |
| C string | c"hello" | &'static CStr | Quote, Byte, Unicode |
| Raw C string | cr#"hello"# | &'static CStr | None |
| Integer | 98_222 0xff 0o77 0b1111 | Any integer type | |
| Floating-point | 3.14 2. 1e10 | f32 or f64 | |
| Boolean | true false | bool |
Escapes
| Escape | Kind | Meaning |
|---|---|---|
\', \" | Quote | Single or double quote |
\n, \r, \t | ASCII and byte | Line feed, carriage return, tab |
\\ | ASCII and byte | Backslash |
\0 | ASCII and byte | Null |
\x41 | ASCII | Exactly two hexadecimal digits, value up to 0x7F |
\xFF | Byte | Exactly two hexadecimal digits, any value |
\u{7FFF} | Unicode | One to six hexadecimal digits in braces; must be a valid Unicode scalar value |
\ then a line feed | String continuation | Removes the line feed and the white space that starts the next line |
Unlike C, there are no \a, \b, \f or
\v escapes and no octal escapes. Use \x08 or
\u{8} for a backspace.
Character literals
One Unicode scalar value, or one quote, ASCII or Unicode escape, in single quotes.
A literal may not contain an unescaped ', \, line feed,
carriage return or tab. A char always holds a whole scalar value, so
'😀' is valid.
String literals
Any sequence of Unicode characters between double quotes. A line feed inside the
literal is part of the string. A carriage return is not allowed. An unescaped
" or \ is not allowed, except for a backslash used as a
string continuation.
let a = "one
two"; // "one\ntwo"
let b = "one \
two"; // "one two"; the continuation removes the line feed and leading spaces
let c = "A\x41\u{41}"; // "AAA"
Raw string literals
A raw string starts with r, then zero to 255 # characters,
then ". It ends at a " followed by the same number of
# characters. Nothing inside is an escape. A carriage return is not
allowed.
r"C:\Temp"; // C:\Temp
r#"She said "hi""#; // She said "hi"
r##"a "# in it"##; // a "# in it
Byte and byte string literals
A byte literal is one ASCII character (U+0000 to U+007F)
or one byte escape between b' and ', and has type
u8. A byte string holds ASCII characters and byte escapes between
b" and ". Its type is a reference to an array of bytes.
Line feeds and string continuations are allowed; carriage returns and non-ASCII
characters are not.
A raw byte string starts with br and is delimited like a raw string.
Only ASCII is allowed in it.
b'R'; b"\x52"; br"R"; // the byte 82, or strings holding it
b"\\x52"; br"\x52"; // the four bytes \ x 5 2
b"foo #\"# bar"; br##"foo #"# bar"##;
C string literals
A C string literal (edition 2021 and later) holds any Unicode characters except
", \, carriage return and NUL, plus byte and
Unicode escapes other than an escape with the value zero. The value is a
&'static CStr with a null byte added at the end; no other null
byte is allowed. Non-ASCII characters are stored as their UTF-8 bytes, and the
literal has no defined encoding beyond that, so c"æ",
c"\u{00E6}" and c"\xC3\xA6" are the same.
A raw C string starts with cr and is delimited like a raw string; it
takes any Unicode character except NUL and carriage return, and has no
escapes. Before edition 2021, c"" reads as the identifier
c followed by "".
Integer literals
| Base | Prefix | Example |
|---|---|---|
| Decimal | none | 98_222 |
| Hexadecimal | 0x | 0xff, 0xFF_u8 |
| Octal | 0o | 0o77 |
| Binary | 0b | 0b1111_0000 |
_may appear anywhere after the first digit, or after the radix prefix if at least one digit follows:0b________1is valid.- A leading zero does not mean octal:
010is the decimal number 10. - An integer has no sign.
-1i8is two tokens, a-and1i8. - A literal too big for its type is rejected by a lint that is deny by default,
not by the grammar.
256_u8is a valid token. - The token is rejected when a digit is out of range for the radix
(
0b0102,0o1279), when a radix prefix has no digit (0b), and for an unsuffixed binary, octal or hexadecimal number directly followed by.and a digit (0x80.0). In these cases it is an error, not two tokens.
Floating-point literals
FLOAT_LITERAL:
DEC_LITERAL . (not immediately followed by ., _ or an XID_Start character)
DEC_LITERAL . DEC_LITERAL SUFFIX?
DEC_LITERAL ( . DEC_LITERAL )? FLOAT_EXPONENT SUFFIX?
FLOAT_EXPONENT:
( e | E ) ( + | - )? ( DEC_DIGIT | _ )* DEC_DIGIT ( DEC_DIGIT | _ )*
1.0,12E+99_f64,0.1f32and2.are floating-point literals.2.f64is a method call on the integer2, and1..2is a range, so a literal may end in a point only when no.,_or letter follows.- An integer literal with an
f32orf64suffix is accepted as a float expression:5f32has typef32. - A number with no digits after the exponent (
2e) is a lexical error. - A float literal has no sign.
-1.0is two tokens.
Suffixes
A suffix is an identifier written directly after a literal, with no white space. At expression or pattern level, only these are accepted; any other suffix, or any suffix on a non-numeric literal, is rejected:
| Literal | Suffixes |
|---|---|
| Integer | u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize |
| Float | f32 f64 |
With no suffix, the type comes from type inference. If nothing constrains it,
integer literals default to i32 and floats to f64. A
literal’s suffix may not begin with e or E unless it is
an exponent; 2em is an error.
Tuple indexes
The number after the dot in t.0 is a tuple index. It uses the same
lexical form as a decimal integer but it is compared as the literal token: no
leading zeros, no underscores, no suffix and no other radix. t.01,
t.0usize and t.0b10 do not refer to a field.
Lifetime and loop label tokens
LIFETIME_TOKEN: ' IDENTIFIER_OR_KEYWORD (not followed by ') | RAW_LIFETIME
LIFETIME_OR_LABEL: ' NON_KEYWORD_IDENTIFIER (not followed by ') | RAW_LIFETIME
RAW_LIFETIME: 'r# IDENTIFIER_OR_KEYWORD (not followed by ')
A lifetime or label is ' followed by an identifier, not closed by another
quote, so 'a is a lifetime and 'a' is a character. The lexer
takes 'static and any keyword after the quote, which a macro can consume;
the grammar for a lifetime parameter or label uses
LIFETIME_OR_LABEL, which excludes keywords. '_ is the
placeholder lifetime.
A raw lifetime, 'r#name (edition 2021 and later), lets a lifetime be
named after a keyword. It may be any strict or reserved keyword except
_, crate, self, Self and
super. Before edition 2021, 'r#lt is read as
'r, # and lt.
Punctuation
Punctuation tokens are operators, separators and parts of the grammar (Reference: Tokens). Their meanings in expressions are on the Expressions page.
| Token | Name | Use |
|---|---|---|
+ - * / % | Arithmetic | Binary arithmetic; - also negates, * also dereferences |
+= -= *= /= %= &= |= ^= <<= >>= | Compound assignment | Operate and assign |
= | Assign | Assignment and initialisers |
== != < > <= >= | Comparison | Also angle brackets for generics (<, >) |
! | Bang | Not; macro invocation (name!); the never type |
& && | And | Bitwise and logical and; borrow; reference types and patterns |
| || | Or | Bitwise and logical or; closure parameters; pattern alternatives |
^ | Caret | Exclusive or |
<< >> | Shift | Bit shifts; >> also closes nested generics |
:: | Path separator | Paths: std::io |
-> | Arrow | Return types of functions and closures |
=> | Fat arrow | Match arms and macro rules |
. | Dot | Field access and method calls |
.. | Range or rest | Ranges; .. in struct and slice patterns; struct update |
..= | Inclusive range | Inclusive ranges and range patterns |
... | Ellipsis | C-variadic parameters; old form of inclusive range patterns |
, | Comma | Separates items |
; | Semicolon | Ends statements and items; array repeat length |
: | Colon | Type annotations, struct fields, bounds |
? | Question mark | The try operator; ?Sized |
@ | At | Bindings in patterns |
_ | Underscore | Wildcard pattern, inferred types; a keyword, not punctuation |
# | Pound | Attributes |
$ | Dollar | Macro metavariables |
~ | Tilde | A token with no stable use |
<- | Left arrow | A token with no stable use |
Delimiters
Brackets are tokens that must always appear in matching pairs: parentheses
( ), square brackets [ ] and braces { }. A
bracketed group is a token tree and macros treat it as a single argument.
Reserved tokens
Some forms are reserved for future use and are errors, so that new literals can be added without changing the meaning of old code (Reference: Tokens).
| Form | Examples | Rule |
|---|---|---|
| Reserved prefixes (edition 2021 and later) | k#ident, f"…", foo'x' | An identifier or keyword directly before #, " or ' is an error, except the existing literal prefixes r, b, br, c and cr. In earlier editions these split into separate tokens. |
| Reserved guarded strings and pounds (edition 2024 and later) | #"foo"#, ## | One or more # directly before a string literal, or two or more # in a row, are errors. In earlier editions these split into separate tokens. |