Токены
Lexer
Token →
RESERVED_TOKEN
| RAW_IDENTIFIER
| CHAR_LITERAL
| STRING_LITERAL
| RAW_STRING_LITERAL
| BYTE_LITERAL
| BYTE_STRING_LITERAL
| RAW_BYTE_STRING_LITERAL
| C_STRING_LITERAL
| RAW_C_STRING_LITERAL
| INTEGER_LITERAL
| FLOAT_LITERAL
| LIFETIME_TOKEN
| PUNCTUATION
| IDENTIFIER_OR_KEYWORD
Токены — это примитивные конструкции в грамматике, определяемые регулярными (нерекурсивными) языками. Исходный код Rust может быть разбит на следующие виды токенов:
- Ключевые словаKeywords
- Идентификаторыidentifier
- Литералы
- Времена жизни
- Знаки пунктуации
- Разделители
В грамматике этой документации “простые” токены представлены в форме продукций таблицы строк
и отображаются шрифтом monospace.
Литералы
Литералы — это токены, используемые в литеральных выражениях.
Примеры
Символы и строки
| Пример | Кол-во #1 | Символы | Экранирования | |
|---|---|---|---|---|
| Символьный | 'H' | 0 | Все Unicode | Кавычки & ASCII & Unicode |
| Строковый | "hello" | 0 | Все Unicode | Кавычки & ASCII & Unicode |
| Сырая строка | r#"hello"# | <256 | Все Unicode | N/A |
| Байтовый | b'H' | 0 | Все ASCII | Кавычки & Байтовые |
| Байтовая строка | b"hello" | 0 | Все ASCII | Кавычки & Байтовые |
| Сырая байтовая строка | br#"hello"# | <256 | Все ASCII | N/A |
| C-строка | c"hello" | 0 | Все Unicode | Кавычки & Байтовые & Unicode |
| Сырая C-строка | cr#"hello"# | <256 | Все Unicode | N/A |
Экранирования ASCII
| Имя | |
|---|---|
\x41 | 7-битный код символа (ровно 2 цифры, до 0x7F) |
\n | Перевод строки (Newline) |
\r | Возврат каретки (Carriage return) |
\t | Табуляция (Tab) |
\\ | Обратная косая черта (Backslash) |
\0 | Нуль (Null) |
Байтовые экранирования
| Имя | |
|---|---|
\x7F | 8-битный код символа (ровно 2 цифры) |
\n | Перевод строки (Newline) |
\r | Возврат каретки (Carriage return) |
\t | Табуляция (Tab) |
\\ | Обратная косая черта (Backslash) |
\0 | Нуль (Null) |
Экранирования Unicode
| Имя | |
|---|---|
\u{7FFF} | 24-битный код символа Unicode (до 6 цифр) |
Экранирования кавычек
| Имя | |
|---|---|
\' | Одинарная кавычка |
\" | Двойная кавычка |
Числа
| Числовые литералы2 | Пример | Экспонента |
|---|---|---|
| Десятичное целое | 98_222 | N/A |
| Шестнадцатеричное целое | 0xff | N/A |
| Восьмеричное целое | 0o77 | N/A |
| Двоичное целое | 0b1111_0000 | N/A |
| Число с плавающей точкой | 123.0E+77 | Опционально |
Суффиксы
Суффикс — это последовательность символов, следующая за основной частью литерала (без пробелов между ними), имеющая ту же форму, что и несырой идентификатор или ключевое слово.
Lexer
SUFFIX → IDENTIFIER_OR_KEYWORDкроме _
SUFFIX_NO_E → SUFFIXне начинающийся с e или E
Любой вид литерала (строковый, целочисленный и т.д.) с любым суффиксом является допустимым токеном.
Токен литерала с любым суффиксом может быть передан в макрос без возникновения ошибки.
Сам макрос решит, как интерпретировать такой токен и следует ли выдавать ошибку.
В частности, спецификатор фрагмента literal для макросов по примеру сопоставляет токены литералов с произвольными суффиксами.
#![allow(unused)] fn main() { macro_rules! blackhole { ($tt:tt) => () } macro_rules! blackhole_lit { ($l:literal) => () } blackhole!("string"suffix); // OK blackhole_lit!(1suffix); // OK }
Однако суффиксы на токенах литералов, которые интерпретируются как литеральные выражения или шаблоны, ограничены. Любые суффиксы отвергаются на нечисловых токенах литералов, а числовые токены литералов принимаются только с суффиксами из списка ниже.
| Целые числа | С плавающей точкой |
|---|---|
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize | f32, f64 |
Символьные и строковые литералы
Символьные литералы
Lexer
CHAR_LITERAL →
'
( ~[' \ LF CR TAB] | QUOTE_ESCAPE | ASCII_ESCAPE | UNICODE_ESCAPE )
' SUFFIX?
QUOTE_ESCAPE → \' | \"
ASCII_ESCAPE →
\x OCT_DIGIT HEX_DIGIT
| \n | \r | \t | \\ | \0
UNICODE_ESCAPE →
\u{ ( HEX_DIGIT _* )1..6 }
Символьный литерал — это одиночный символ Unicode, заключённый между двумя
символами U+0027 (одинарная кавычка), за исключением самого U+0027,
который должен быть экранирован предшествующим символом U+005C (\).
Строковые литералы
Lexer
STRING_LITERAL →
" (
~[" \ CR]
| QUOTE_ESCAPE
| ASCII_ESCAPE
| UNICODE_ESCAPE
| STRING_CONTINUE
)* " SUFFIX?
STRING_CONTINUE → \ LF
Строковый литерал — это последовательность любых символов Unicode, заключённая между двумя
символами U+0022 (двойная кавычка), за исключением самого U+0022,
который должен быть экранирован предшествующим символом U+005C (\).
Разрывы строк, представленные символом U+000A (LF), допускаются в строковых литералах.
Символ U+000D (CR) не может появляться в строковом литерале.
Когда неэкранированный символ U+005C (\) встречается непосредственно перед разрывом строки, разрыв строки не появляется в строке, представленной токеном.
Подробнее см. Экранирования продолжения строки.
Символьные экранирования
Некоторые дополнительные экранирования доступны либо в символьных, либо в несырых строковых
литералах. Экранирование начинается с U+005C (\) и продолжается одной из
следующих форм:
- 7-битное экранирование кодовой точки начинается с
U+0078(x) и следует ровно две шестнадцатеричные цифры со значением до0x7F. Оно обозначает символ ASCII со значением, равным предоставленному шестнадцатеричному значению. Более высокие значения не допускаются, поскольку неясно, означают ли они кодовые точки Unicode или байтовые значения.
- 24-битное экранирование кодовой точки начинается с
U+0075(u) и следует до шести шестнадцатеричных цифр, окружённых фигурными скобкамиU+007B({) иU+007D(}). Оно обозначает кодовую точку Unicode, равную предоставленному шестнадцатеричному значению.
- Экранирование пробельного символа — это один из символов
U+006E(n),U+0072(r) илиU+0074(t), обозначающих значения UnicodeU+000A(LF),U+000D(CR) илиU+0009(HT) соответственно.
- Нулевое экранирование — это символ
U+0030(0) и обозначает значение UnicodeU+0000(NUL).
- Экранирование обратной косой черты — это символ
U+005C(\), который должен быть экранирован, чтобы обозначить сам себя.
Сырые строковые литералы
Lexer
RAW_STRING_LITERAL → r RAW_STRING_CONTENT SUFFIX?
RAW_STRING_CONTENT →
" ( ~CR )* (non-greedy) "
| # RAW_STRING_CONTENT #
Сырые строковые литералы не обрабатывают никакие экранирования. Они начинаются с символа
U+0072 (r), за которым следует менее 256 символов U+0023 (#) и
символ U+0022 (двойная кавычка).
Тело сырой строки может содержать любую последовательность символов Unicode, кроме U+000D (CR).
Оно завершается только другим символом U+0022 (двойная кавычка), за которым следует то же количество символов U+0023 (#), которое предшествовало открывающему символу U+0022 (двойная кавычка).
Все символы Unicode, содержащиеся в теле сырой строки, представляют самих себя,
символы U+0022 (двойная кавычка) (кроме случая, когда за ними следует по крайней мере
столько же символов U+0023 (#), сколько было использовано для начала сырого строкового литерала) или
U+005C (\) не имеют никакого специального значения.
Примеры строковых литералов:
#![allow(unused)] fn main() { "foo"; r"foo"; // foo "\"foo\""; r#""foo""#; // "foo" "foo #\"# bar"; r##"foo #"# bar"##; // foo #"# bar "\x52"; "R"; r"R"; // R "\\x52"; r"\x52"; // \x52 }
Байтовые и байтовые строковые литералы
Байтовые литералы
Lexer
BYTE_LITERAL →
b' ( ASCII_FOR_CHAR | BYTE_ESCAPE ) ' SUFFIX?
ASCII_FOR_CHAR →
<любой ASCII (т.е. 0x00 до 0x7F) кроме ', \, LF, CR или TAB>
BYTE_ESCAPE →
\x HEX_DIGIT HEX_DIGIT
| \n | \r | \t | \\ | \0 | \' | \"
Байтовый литерал — это одиночный символ ASCII (в диапазоне U+0000 до U+007F)
или одиночное экранирование, перед которым стоят символы U+0062 (b) и
U+0027 (одинарная кавычка), и после которого следует символ U+0027. Если символ
U+0027 присутствует внутри литерала, он должен быть экранирован предшествующим
символом U+005C (\). Он эквивалентен числовому литералу беззнакового 8-битного целого числа u8.
Байтовые строковые литералы
Lexer
BYTE_STRING_LITERAL →
b" ( ASCII_FOR_STRING | BYTE_ESCAPE | STRING_CONTINUE )* " SUFFIX?
ASCII_FOR_STRING →
<любой ASCII (т.е 0x00 до 0x7F) кроме ", \ или CR>
Несырой байтовый строковый литерал — это последовательность символов ASCII и экранирований,
перед которой стоят символы U+0062 (b) и U+0022 (двойная кавычка), и
после которой следует символ U+0022. Если символ U+0022 присутствует внутри
литерала, он должен быть экранирован предшествующим символом U+005C (\).
Альтернативно, байтовый строковый литерал может быть сырым байтовым строковым литералом, определённым
ниже.
Разрывы строк, представленные символом U+000A (LF), допускаются в байтовых строковых литералах.
Символ U+000D (CR) не может появляться в байтовом строковом литерале.
Когда неэкранированный символ U+005C (\) встречается непосредственно перед разрывом строки, разрыв строки не появляется в строке, представленной токеном.
Подробнее см. Экранирования продолжения строки.
Некоторые дополнительные экранирования доступны либо в байтовых, либо в несырых байтовых строковых
литералах. Экранирование начинается с U+005C (\) и продолжается одной из
следующих форм:
- Байтовое экранирование начинается с
U+0078(x) и следует ровно две шестнадцатеричные цифры. Оно обозначает байт, равный предоставленному шестнадцатеричному значению.
- Экранирование пробельного символа — это один из символов
U+006E(n),U+0072(r) илиU+0074(t), обозначающих байтовые значения0x0A(ASCII LF),0x0D(ASCII CR) или0x09(ASCII HT) соответственно.
- Нулевое экранирование — это символ
U+0030(0) и обозначает байтовое значение0x00(ASCII NUL).
- Экранирование обратной косой черты — это символ
U+005C(\), который должен быть экранирован, чтобы обозначить своё ASCII-представление0x5C.
Сырые байтовые строковые литералы
Lexer
RAW_BYTE_STRING_LITERAL →
br RAW_BYTE_STRING_CONTENT SUFFIX?
RAW_BYTE_STRING_CONTENT →
" ASCII_FOR_RAW* (non-greedy) "
| # RAW_BYTE_STRING_CONTENT #
ASCII_FOR_RAW →
<любой ASCII (т.е. 0x00 до 0x7F) кроме CR>
Сырые байтовые строковые литералы не обрабатывают никакие экранирования. Они начинаются с
символа U+0062 (b), за которым следует U+0072 (r), за которым следует менее 256
символов U+0023 (#) и символ U+0022 (двойная кавычка).
Тело сырой строки может содержать любую последовательность символов ASCII, кроме U+000D (CR).
Оно завершается только другим символом U+0022 (двойная кавычка), за которым следует то же количество символов U+0023 (#), которое предшествовало открывающему символу U+0022 (двойная кавычка).
Сырой байтовый строковый литерал не может содержать никаких не-ASCII байтов.
Все символы, содержащиеся в теле сырой строки, представляют своё ASCII-представление,
символы U+0022 (двойная кавычка) (кроме случая, когда за ними следует по крайней мере
столько же символов U+0023 (#), сколько было использовано для начала сырого строкового литерала) или
U+005C (\) не имеют никакого специального значения.
Примеры байтовых строковых литералов:
#![allow(unused)] fn main() { b"foo"; br"foo"; // foo b"\"foo\""; br#""foo""#; // "foo" b"foo #\"# bar"; br##"foo #"# bar"##; // foo #"# bar b"\x52"; b"R"; br"R"; // R b"\\x52"; br"\x52"; // \x52 }
C-строковые и сырые C-строковые литералы
C-строковые литералы
Lexer
C_STRING_LITERAL →
c" (
~[" \ CR NUL]
| BYTE_ESCAPEкроме \0 или \x00
| UNICODE_ESCAPEкроме \u{0}, \u{00}, …, \u{000000}
| STRING_CONTINUE
)* " SUFFIX?
C-строковый литерал — это последовательность символов Unicode и экранирований,
перед которой стоят символы U+0063 (c) и U+0022 (двойная кавычка), и
после которой следует символ U+0022. Если символ U+0022 присутствует внутри
литерала, он должен быть экранирован предшествующим символом U+005C (\).
Альтернативно, C-строковый литерал может быть сырым C-строковым литералом, определённым ниже.
C-строки неявно завершаются байтом 0x00, поэтому C-строковый литерал
c"" эквивалентен ручному созданию &CStr из байтового строкового
литерала b"\x00". Кроме неявного терминатора, байт 0x00 не
допускается внутри C-строки.
Разрывы строк, представленные символом U+000A (LF), допускаются в C-строковых литералах.
Символ U+000D (CR) не может появляться в C-строковом литерале.
Когда неэкранированный символ U+005C (\) встречается непосредственно перед разрывом строки, разрыв строки не появляется в строке, представленной токеном.
Подробнее см. Экранирования продолжения строки.
Некоторые дополнительные экранирования доступны в несырых C-строковых литералах. Экранирование
начинается с U+005C (\) и продолжается одной из следующих форм:
- Байтовое экранирование начинается с
U+0078(x) и следует ровно две шестнадцатеричные цифры. Оно обозначает байт, равный предоставленному шестнадцатеричному значению.
- 24-битное экранирование кодовой точки начинается с
U+0075(u) и следует до шести шестнадцатеричных цифр, окружённых фигурными скобкамиU+007B({) иU+007D(}). Оно обозначает кодовую точку Unicode, равную предоставленному шестнадцатеричному значению, закодированную как UTF-8.
- Экранирование пробельного символа — это один из символов
U+006E(n),U+0072(r) илиU+0074(t), обозначающих байтовые значения0x0A(ASCII LF),0x0D(ASCII CR) или0x09(ASCII HT) соответственно.
- Экранирование обратной косой черты — это символ
U+005C(\), который должен быть экранирован, чтобы обозначить своё ASCII-представление0x5C.
C-строка представляет байты без определённой кодировки, но C-строковый литерал
может содержать символы Unicode выше U+007F. Такие символы будут заменены
байтами UTF-8 представления этого символа.
Следующие C-строковые литералы эквивалентны:
#![allow(unused)] fn main() { c"æ"; // LATIN SMALL LETTER AE (U+00E6) c"\u{00E6}"; c"\xC3\xA6"; }
2021 Edition differences
C-строковые литералы принимаются в редакции 2021 или позже. В более ранних редакциях токен
c""лексируется какc "".
Сырые C-строковые литералы
Lexer
RAW_C_STRING_LITERAL →
cr RAW_C_STRING_CONTENT SUFFIX?
RAW_C_STRING_CONTENT →
" ( ~[CR NUL] )* (non-greedy) "
| # RAW_C_STRING_CONTENT #
Сырые C-строковые литералы не обрабатывают никакие экранирования. Они начинаются с
символа U+0063 (c), за которым следует U+0072 (r), за которым следует менее 256
символов U+0023 (#) и символ U+0022 (двойная кавычка).
Тело сырой C-строки может содержать любую последовательность символов Unicode, кроме U+0000 (NUL) и U+000D (CR).
Оно завершается только другим символом U+0022 (двойная кавычка), за которым следует то же количество символов U+0023 (#), которое предшествовало открывающему символу U+0022 (двойная кавычка).
Все символы, содержащиеся в теле сырой C-строки, представляют самих себя в кодировке UTF-8.
Символы U+0022 (двойная кавычка) (кроме случая, когда за ними следует по крайней мере
столько же символов U+0023 (#), сколько было использовано для начала сырого C-строкового
литерала) или U+005C (\) не имеют никакого специального значения.
2021 Edition differences
Сырые C-строковые литералы принимаются в редакции 2021 или позже. В более ранних редакциях токен
cr""лексируется какcr "", аcr#""#лексируется какcr #""#(что неграмматично).
Примеры C-строковых и сырых C-строковых литералов
#![allow(unused)] fn main() { c"foo"; cr"foo"; // foo c"\"foo\""; cr#""foo""#; // "foo" c"foo #\"# bar"; cr##"foo #"# bar"##; // foo #"# bar c"\x52"; c"R"; cr"R"; // R c"\\x52"; cr"\x52"; // \x52 }
Целочисленные литералы
Lexer
INTEGER_LITERAL →
( DEC_LITERAL | BIN_LITERAL | OCT_LITERAL | HEX_LITERAL ) SUFFIX_NO_E?
DEC_LITERAL → DEC_DIGIT ( DEC_DIGIT | _ )*
BIN_LITERAL → 0b ( BIN_DIGIT | _ )* BIN_DIGIT ( BIN_DIGIT | _ )*
OCT_LITERAL → 0o ( OCT_DIGIT | _ )* OCT_DIGIT ( OCT_DIGIT | _ )*
HEX_LITERAL → 0x ( HEX_DIGIT | _ )* HEX_DIGIT ( HEX_DIGIT | _ )*
BIN_DIGIT → [0-1]
OCT_DIGIT → [0-7]
DEC_DIGIT → [0-9]
HEX_DIGIT → [0-9 a-f A-F]
Целочисленный литерал имеет одну из четырёх форм:
- Десятичный литерал начинается с десятичной цифры и продолжается любым сочетанием десятичных цифр и знаков подчёркивания.
- Шестнадцатеричный литерал начинается с последовательности символов
U+0030U+0078(0x) и продолжается любым сочетанием (с как минимум одной цифрой) шестнадцатеричных цифр и знаков подчёркивания.
- Восьмеричный литерал начинается с последовательности символов
U+0030U+006F(0o) и продолжается любым сочетанием (с как минимум одной цифрой) восьмеричных цифр и знаков подчёркивания.
- Двоичный литерал начинается с последовательности символов
U+0030U+0062(0b) и продолжается любым сочетанием (с как минимум одной цифрой) двоичных цифр и знаков подчёркивания.
Как и любой литерал, целочисленный литерал может следовать (непосредственно, без пробелов) за суффиксом, как описано выше.
Суффикс не может начинаться с e или E, так как это будет интерпретировано как экспонента литерала с плавающей точкой.
См. Целочисленные литеральные выражения для получения информации о влиянии этих суффиксов.
Примеры целочисленных литералов, которые принимаются как литеральные выражения:
#![allow(unused)] fn main() { #![allow(overflowing_literals)] 123; 123i32; 123u32; 123_u32; 0xff; 0xff_u8; 0x01_f32; // целое число 7986, не число с плавающей точкой 1.0 0x01_e3; // целое число 483, не число с плавающей точкой 1000.0 0o70; 0o70_i16; 0b1111_1111_1001_0000; 0b1111_1111_1001_0000i64; 0b________1; 0usize; // Эти числа слишком велики для своего типа, но принимаются как литеральные выражения. 128_i8; 256_u8; // Это целочисленный литерал, принимаемый как литеральное выражение с плавающей точкой. 5f32; }
Обратите внимание, что -1i8, например, анализируется как два токена: - followed by 1i8.
Примеры целочисленных литералов, которые не принимаются как литеральные выражения:
#![allow(unused)] fn main() { #[cfg(false)] { 0invalidSuffix; 123AFB43; 0b010a; 0xAB_CD_EF_GH; 0b1111_f32; } }
Индекс кортежа
Lexer
TUPLE_INDEX → DEC_LITERAL | BIN_LITERAL | OCT_LITERAL | HEX_LITERAL
Индекс кортежа используется для обращения к полям кортежей, кортежных структур и кортежных вариантов перечислений.
Индексы кортежа сравниваются с токеном литерала напрямую. Индексы кортежа
начинаются с 0, и каждый последующий индекс увеличивает значение на 1 как
десятичное значение. Таким образом, совпадут только десятичные значения, и значение не должно
иметь никаких лишних префиксных символов 0.
Индексы кортежа не могут включать никакие суффиксы (такие как usize).
#![allow(unused)] fn main() { let example = ("dog", "cat", "horse"); let dog = example.0; let cat = example.1; // Следующие примеры недопустимы. let cat = example.01; // ОШИБКА: нет поля с именем `01` let horse = example.0b10; // ОШИБКА: нет поля с именем `0b10` let unicorn = example.0usize; // ОШИБКА: суффиксы в индексе кортежа недопустимы let underscore = example.0_0; // ОШИБКА: нет поля `0_0` в типе `(&str, &str, &str)` }
Литералы с плавающей точкой
Lexer
FLOAT_LITERAL →
DEC_LITERAL .not immediately followed by ., _ or an XID_Start character
| DEC_LITERAL . DEC_LITERAL SUFFIX_NO_E?
| DEC_LITERAL ( . DEC_LITERAL )? FLOAT_EXPONENT SUFFIX?
FLOAT_EXPONENT →
( e | E ) ( + | - )? ( DEC_DIGIT | _ )* DEC_DIGIT ( DEC_DIGIT | _ )*
Литерал с плавающей точкой имеет одну из двух форм:
- Десятичный литерал, за которым следует символ точки
U+002E(.). За этим может следовать другой десятичный литерал, с необязательной экспонентой. - Одиночный десятичный литерал, за которым следует экспонента.
Как и целочисленные литералы, литерал с плавающей точкой может следовать за
суффиксом, при условии, что часть до суффикса не заканчивается на U+002E (.).
Суффикс не может начинаться с e или E, если литерал не включает экспоненту.
См. Выражения литералов с плавающей точкой для получения информации о влиянии этих суффиксов.
Примеры литералов с плавающей точкой, которые принимаются как литеральные выражения:
#![allow(unused)] fn main() { 123.0f64; 0.1f64; 0.1f32; 12E+99_f64; let x: f64 = 2.; }
Последний пример отличается, потому что невозможно использовать синтаксис суффикса
с литералом с плавающей точкой, заканчивающимся на точку. 2.f64 попытается
вызвать метод с именем f64 на 2.
Обратите внимание, что -1.0, например, анализируется как два токена: - followed by 1.0.
Примеры литералов с плавающей точкой, которые не принимаются как литеральные выражения:
#![allow(unused)] fn main() { #[cfg(false)] { 2.0f80; 2e5f80; 2e5e6; 2.0e5e6; 1.3e10u64; } }
Зарезервированные формы, похожие на числовые литералы
Lexer
RESERVED_NUMBER →
BIN_LITERAL [2-9]
| OCT_LITERAL [8-9]
| ( BIN_LITERAL | OCT_LITERAL | HEX_LITERAL ) .not immediately followed by ., _ or an XID_Start character
| ( BIN_LITERAL | OCT_LITERAL ) ( e | E )
| 0b _* <end of input or not BIN_DIGIT>
| 0o _* <end of input or not OCT_DIGIT>
| 0x _* <end of input or not HEX_DIGIT>
| DEC_LITERAL ( . DEC_LITERAL )? ( e | E ) ( + | - )? <end of input or not DEC_DIGIT>
Следующие лексические формы, похожие на числовые литералы, являются зарезервированными формами. Из-за возможной неоднозначности, которую они вызывают, они отвергаются токенизатором вместо того, чтобы интерпретироваться как отдельные токены.
- Несуффиксированный двоичный или восьмеричный литерал, за которым, без пробелов, следует десятичная цифра вне диапазона его системы счисления.
- Несуффиксированный двоичный, восьмеричный или шестнадцатеричный литерал, за которым, без пробелов, следует символ точки (с теми же ограничениями на то, что следует за точкой, как для литералов с плавающей точкой).
- Несуффиксированный двоичный или восьмеричный литерал, за которым, без пробелов, следует символ
eилиE.
- Ввод, который начинается с одного из префиксов системы счисления, но не является допустимым двоичным, восьмеричным или шестнадцатеричным литералом (потому что не содержит цифр).
- Ввод, который имеет форму литерала с плавающей точкой без цифр в экспоненте.
Примеры зарезервированных форм:
#![allow(unused)] fn main() { 0b0102; // это не `0b010` followed by `2` 0o1279; // это не `0o127` followed by `9` 0x80.0; // это не `0x80` followed by `.` и `0` 0b101e; // это не суффиксированный литерал, или `0b101` followed by `e` 0b; // это не целочисленный литерал, или `0` followed by `b` 0b_; // это не целочисленный литерал, или `0` followed by `b_` 2e; // это не литерал с плавающей точкой, или `2` followed by `e` 2.0e; // это не литерал с плавающей точкой, или `2.0` followed by `e` 2em; // это не суффиксированный литерал, или `2` followed by `em` 2.0em; // это не суффиксированный литерал, или `2.0` followed by `em` }
Времена жизни и метки циклов
Lexer
LIFETIME_TOKEN →
' IDENTIFIER_OR_KEYWORDnot immediately followed by '
| RAW_LIFETIME
LIFETIME_OR_LABEL →
' NON_KEYWORD_IDENTIFIERnot immediately followed by '
| RAW_LIFETIME
RAW_LIFETIME →
'r# IDENTIFIER_OR_KEYWORDnot immediately followed by '
RESERVED_RAW_LIFETIME → 'r# ( _ | crate | self | Self | super )not immediately followed by '
Параметры времени жизни и метки циклов используют токены LIFETIME_OR_LABEL. Любой токен LIFETIME_TOKEN будет принят лексером и, например, может быть использован в макросах.
Сырое время жизни похоже на обычное время жизни, но его идентификатор имеет префикс r#. (Обратите внимание, что префикс r# не включается в состав самого времени жизни.)
В отличие от обычного времени жизни, сырым временем жизни может быть любое строгое или зарезервированное ключевое слово, кроме перечисленных выше для RESERVED_RAW_LIFETIME.
Ошибкой является использование токена RESERVED_RAW_LIFETIME.
2021 Edition differences
Сырые времена жизни принимаются в редакции 2021 или позже. В более ранних редакциях токен
'r#ltлексируется как'r # lt.
Знаки пунктуации
Токены пунктуации используются как операторы, разделители и другие части грамматики.
Lexer
PUNCTUATION →
=
| <
| <=
| ==
| !=
| >=
| >
| &&
| ||
| !
| ~
| +
| -
| *
| /
| %
| ^
| &
| |
| <<
| >>
| +=
| -=
| *=
| /=
| %=
| ^=
| &=
| |=
| <<=
| >>=
| @
| .
| ..
| ...
| ..=
| ,
| ;
| :
| ::
| ->
| <-
| =>
| #
| $
| ?
| {
| }
| [
| ]
| (
| )
Note
См. синтаксический указатель для ссылок на то, как используются символы пунктуации.
Разделители
Скобочные знаки пунктуации используются в различных частях грамматики. Открывающая скобка всегда должна быть парной с закрывающей скобкой. Скобки и токены внутри них называются “деревьями токенов” в macros. Три типа скобок:
| Скобка | Тип |
|---|---|
{ } | Фигурные скобки |
[ ] | Квадратные скобки |
( ) | Круглые скобки |
Зарезервированные токены
Несколько форм токенов зарезервированы для будущего использования или чтобы избежать путаницы. Ошибкой является совпадение исходного ввода с одной из этих форм.
Lexer
RESERVED_TOKEN →
RESERVED_GUARDED_STRING_LITERAL
| RESERVED_NUMBER
| RESERVED_POUNDS
| RESERVED_RAW_IDENTIFIER
| RESERVED_RAW_LIFETIME
| RESERVED_TOKEN_DOUBLE_QUOTE
| RESERVED_TOKEN_LIFETIME
| RESERVED_TOKEN_POUND
| RESERVED_TOKEN_SINGLE_QUOTE
Зарезервированные префиксы
Lexer
RESERVED_TOKEN_DOUBLE_QUOTE →
IDENTIFIER_OR_KEYWORDкроме b или c или r или br или cr "
RESERVED_TOKEN_SINGLE_QUOTE →
IDENTIFIER_OR_KEYWORDкроме b '
RESERVED_TOKEN_POUND →
IDENTIFIER_OR_KEYWORDкроме r или br или cr #
RESERVED_TOKEN_LIFETIME →
' IDENTIFIER_OR_KEYWORDкроме r #
Некоторые лексические формы, известные как зарезервированные префиксы, зарезервированы для будущего использования.
Исходный ввод, который в противном случае лексически интерпретировался бы как несырой идентификатор (или ключевое слово), за которым непосредственно следует символ #, ' или " (без пробелов между ними), идентифицируется как зарезервированный префикс.
Обратите внимание, что сырые идентификаторы, сырые строковые литералы и сырые байтовые строковые литералы могут содержать символ #, но не интерпретируются как содержащие зарезервированный префикс.
Аналогично, префиксы r, b, br, c и cr, используемые в сырых строковых литералах, байтовых литералах, байтовых строковых литералах, сырых байтовых строковых литералах, C-строковых литералах и сырых C-строковых литералах, не интерпретируются как зарезервированные префиксы.
Исходный ввод, который в противном случае лексически интерпретировался бы как несырое время жизни (или ключевое слово), за которым непосредственно следует символ # (без пробелов между ними), идентифицируется как зарезервированный префикс времени жизни.
2021 Edition differences
Начиная с редакции 2021, зарезервированные префиксы сообщаются лексером как ошибка (в частности, они не могут быть переданы в макросы).
До редакции 2021, зарезервированные префиксы принимаются лексером и интерпретируются как несколько токенов (например, один токен для идентификатора или ключевого слова, за которым следует токен
#).Примеры, принимаемые во всех редакциях:
#![allow(unused)] fn main() { macro_rules! lexes {($($_:tt)*) => {}} lexes!{a #foo} lexes!{continue 'foo} lexes!{match "..." {}} lexes!{r#let#foo} // три токена: r#let # foo lexes!{'prefix #lt} }Примеры, принимаемые до редакции 2021, но отвергаемые позже:
#![allow(unused)] fn main() { macro_rules! lexes {($($_:tt)*) => {}} lexes!{a#foo} lexes!{continue'foo} lexes!{match"..." {}} lexes!{'prefix#lt} }
Зарезервированные ограничители
Lexer
RESERVED_GUARDED_STRING_LITERAL → #+ STRING_LITERAL
RESERVED_POUNDS → #2..
Зарезервированные ограничители — это синтаксис, зарезервированный для будущего использования, и они вызовут ошибку компиляции, если будут использованы.
Зарезервированный ограниченный строковый литерал — это токен из одного или более U+0023 (#), за которым непосредственно следует STRING_LITERAL.
Зарезервированные решётки — это токен из двух или более U+0023 (#).
2024 Edition differences
До редакции 2024, зарезервированные ограничители принимаются лексером и интерпретируются как несколько токенов. Например, форма
#"foo"#интерпретируется как три токена.##интерпретируется как два токена.