Token

Token 是由正则(非递归)语言定义的语法中的基本产生式。Rust 源代码输入可以分解为以下几种 token

在本文档的语法中,“简单” token 以 字符串表产生式 形式给出,并以 monospace 字体显示。

字面量

字面量是在 字面量表达式 中使用的 token。

示例

字符和字符串

示例# 集合1字符转义符
字符'H'0所有 Unicode引号 & ASCII & Unicode
字符串"hello"0所有 Unicode引号 & ASCII & Unicode
原始字符串r#"hello"#<256所有 UnicodeN/A
字节b'H'0所有 ASCII引号 & 字节
字节字符串b"hello"0所有 ASCII引号 & 字节
原始字节字符串br#"hello"#<256所有 ASCIIN/A
C 字符串c"hello"0所有 Unicode引号 & 字节 & Unicode
原始 C 字符串cr#"hello"#<256所有 UnicodeN/A
1

每个字面量两侧 # 的数量必须相等。

注意:字符和字符串字面量 token 永远不包含紧跟 U+000A (LF) 的 U+000D (CR) 序列:这对序列之前会被转换为单个 U+000A (LF)。

ASCII 转义符

名称
\x417 位字符代码(正好 2 位数字,最大到 0x7F)
\n换行符
\r回车符
\t制表符
\\反斜杠
\0空字符

字节转义符

名称
\x7F8 位字符代码(正好 2 位数字)
\n换行符
\r回车符
\t制表符
\\反斜杠
\0空字符

Unicode 转义符

名称
\u{7FFF}24 位 Unicode 字符代码(最多 6 位数字)

引号转义符

名称
\'单引号
\"双引号

数字

数字字面量2示例指数
十进制整数98_222N/A
十六进制整数0xffN/A
八进制整数0o77N/A
二进制整数0b1111_0000N/A
浮点数123.0E+77可选
2

所有数字字面量都允许使用 _ 作为视觉分隔符:1_234.0E+18f64

后缀

后缀是字面量主要部分之后(没有中间的空白符)的字符序列,与非原始标识符或关键字的形式相同。

词法分析器
SUFFIX : IDENTIFIER_OR_KEYWORD
SUFFIX_NO_E : SUFFIX 不以 eE 开头

任何带有任何后缀的字面量(字符串、整数等)作为 token 都是有效的。

带有任何后缀的字面量 token 都可以传递给宏而不会产生错误。宏本身将决定如何解释这样的 token 以及是否产生错误。特别是,用于按示例宏的 literal 片段说明符匹配带有任意后缀的字面量 token。

#![allow(unused)]
fn main() {
macro_rules! blackhole { ($tt:tt) => () }
macro_rules! blackhole_lit { ($l:literal) => () }

blackhole!("string"suffix); // OK
blackhole_lit!(1suffix); // OK
}

但是,解释为字面量表达式或模式的字面量 token 上的后缀是受限制的。非数字字面量 token 上的任何后缀都会被拒绝,而数字字面量 token 仅接受来自以下列表的后缀。

整数浮点数
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isizef32, f64

字符和字符串字面量

字符字面量

词法分析器
CHAR_LITERAL
   ' ( ~[' \ \n \r \t] | 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 }

字符字面量 是用两个 U+0027(单引号)字符括起来的单个 Unicode 字符,但 U+0027 本身除外,它必须由前面的 U+005C 字符 (\) 转义

字符串字面量

词法分析器
STRING_LITERAL
   " (
      ~[" \ IsolatedCR]
      | QUOTE_ESCAPE
      | ASCII_ESCAPE
      | UNICODE_ESCAPE
      | STRING_CONTINUE
   )* " SUFFIX?

STRING_CONTINUE
   \ 后跟 \n

字符串字面量 是用两个 U+0022(双引号)字符括起来的任何 Unicode 字符序列,但 U+0022 本身除外,它必须由前面的 U+005C 字符 (\) 转义

字符串字面量中允许换行符,由字符 U+000A (LF) 表示。当未转义的 U+005C 字符 (\) 紧接在换行符之前出现时,换行符不会出现在 token 表示的字符串中。有关详细信息,请参阅 字符串延续转义符。字符 U+000D (CR) 不得出现在字符串字面量中,除非作为此类字符串延续转义符的一部分。

字符转义符

一些额外的转义符在字符或非原始字符串字面量中可用。转义符以 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) 之一,分别表示 Unicode 值 U+000A (LF)、U+000D (CR) 或 U+0009 (HT)。
  • 空字符转义符 是字符 U+0030 (0),表示 Unicode 值 U+0000 (NUL)。
  • 反斜杠转义符 是字符 U+005C (\),必须对其进行转义才能表示自身。

原始字符串字面量

词法分析器
RAW_STRING_LITERAL
   r RAW_STRING_CONTENT SUFFIX?

RAW_STRING_CONTENT
      " ( ~ IsolatedCR )* (非贪婪) "
   | # RAW_STRING_CONTENT #

原始字符串字面量不处理任何转义符。它们以字符 U+0072 (r) 开头,后跟少于 256 个字符 U+0023 (#) 和一个 U+0022(双引号)字符。

原始字符串主体 可以包含除 U+000D (CR) 之外的任何 Unicode 字符序列。它仅由另一个 U+0022(双引号)字符终止,后跟与开头的 U+0022(双引号)字符之前的 U+0023 (#) 字符数量相同的字符。

原始字符串主体中包含的所有 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
}

字节和字节字符串字面量

字节字面量

词法分析器
BYTE_LITERAL
   b' ( ASCII_FOR_CHAR | BYTE_ESCAPE ) ' SUFFIX?

ASCII_FOR_CHAR
   任何 ASCII (即 0x00 到 0x7F),除了 ', \, \n, \r 或 \t

BYTE_ESCAPE
      \x HEX_DIGIT HEX_DIGIT
   | \n | \r | \t | \\ | \0 | \' | \"

字节字面量 是单个 ASCII 字符(在 U+0000U+007F 范围内)或单个 转义符,前面是字符 U+0062 (b) 和 U+0027(单引号),后面是字符 U+0027。如果字符 U+0027 出现在字面量中,则必须由前面的 U+005C (\) 字符 转义。它等效于 u8 无符号 8 位整数数字字面量

字节字符串字面量

词法分析器
BYTE_STRING_LITERAL
   b" ( ASCII_FOR_STRING | BYTE_ESCAPE | STRING_CONTINUE )* " SUFFIX?

ASCII_FOR_STRING
   任何 ASCII (即 0x00 到 0x7F),除了 ", \ 和 IsolatedCR

非原始字节字符串字面量 是 ASCII 字符和转义符的序列,前面是字符 U+0062 (b) 和 U+0022(双引号),后面是字符 U+0022。如果字符 U+0022 出现在字面量中,则必须由前面的 U+005C (\) 字符 转义。或者,字节字符串字面量可以是原始字节字符串字面量,定义如下。

字节字符串字面量中允许换行符,由字符 U+000A (LF) 表示。当未转义的 U+005C 字符 (\) 紧接在换行符之前出现时,换行符不会出现在 token 表示的字符串中。有关详细信息,请参阅 字符串延续转义符。字符 U+000D (CR) 不得出现在字节字符串字面量中,除非作为此类字符串延续转义符的一部分。

一些额外的转义符在字节或非原始字节字符串字面量中可用。转义符以 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

原始字节字符串字面量

词法分析器
RAW_BYTE_STRING_LITERAL
   br RAW_BYTE_STRING_CONTENT SUFFIX?

RAW_BYTE_STRING_CONTENT
      " ASCII_FOR_RAW* (非贪婪) "
   | # RAW_BYTE_STRING_CONTENT #

ASCII_FOR_RAW
   任何 ASCII (即 0x00 到 0x7F),除了 IsolatedCR

原始字节字符串字面量不处理任何转义符。它们以字符 U+0062 (b) 开头,后跟 U+0072 (r),后跟少于 256 个字符 U+0023 (#),以及一个 U+0022(双引号)字符。

原始字符串主体 可以包含除 U+000D (CR) 之外的任何 ASCII 字符序列。它仅由另一个 U+0022(双引号)字符终止,后跟与开头的 U+0022(双引号)字符之前的 U+0023 (#) 字符数量相同的字符。原始字节字符串字面量不能包含任何非 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 字符串字面量

词法分析器
C_STRING_LITERAL
   c" (
      ~[" \ IsolatedCR 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"" 等效于手动从字节字符串字面量 b"\x00" 构造 &CStr。除了隐式终止符外,字节 0x00 在 C 字符串中是不允许的。

C 字符串字面量中允许换行符,由字符 U+000A (LF) 表示。当未转义的 U+005C 字符 (\) 紧接在换行符之前出现时,换行符不会出现在 token 表示的字符串中。有关详细信息,请参阅 字符串延续转义符。字符 U+000D (CR) 不得出现在 C 字符串字面量中,除非作为此类字符串延续转义符的一部分。

一些额外的转义符在非原始 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 字符串字面量可能包含高于 U+007F 的 Unicode 字符。此类字符将被替换为该字符的 UTF-8 表示形式的字节。

以下 C 字符串字面量是等效的

#![allow(unused)]
fn main() {
c"æ";        // LATIN SMALL LETTER AE (U+00E6)
c"\u{00E6}";
c"\xC3\xA6";
}

版本差异:C 字符串字面量在 2021 版本或更高版本中被接受。在早期版本中,token c"" 被词法分析为 c ""

原始 C 字符串字面量

词法分析器
RAW_C_STRING_LITERAL
   cr RAW_C_STRING_CONTENT SUFFIX?

RAW_C_STRING_CONTENT
      " ( ~ IsolatedCR NUL )* (非贪婪) "
   | # RAW_C_STRING_CONTENT #

原始 C 字符串字面量不处理任何转义符。它们以字符 U+0063 (c) 开头,后跟 U+0072 (r),后跟少于 256 个字符 U+0023 (#),以及一个 U+0022(双引号)字符。

原始 C 字符串主体 可以包含除 U+0000 (NUL) 和 U+000D (CR) 之外的任何 Unicode 字符序列。它仅由另一个 U+0022(双引号)字符终止,后跟与开头的 U+0022(双引号)字符之前的 U+0023 (#) 字符数量相同的字符。

原始 C 字符串主体中包含的所有字符都以 UTF-8 编码形式表示自身。字符 U+0022(双引号)(除非后跟至少与用于启动原始 C 字符串字面量的 U+0023 (#) 字符一样多的字符)或 U+005C (\) 没有任何特殊含义。

版本差异:原始 C 字符串字面量在 2021 版本或更高版本中被接受。在早期版本中,token 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
}

数字字面量

数字字面量整数文字浮点数文字。识别这两种字面量的语法是混合的。

整数文字

词法分析器
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+0030 U+0078 (0x) 开头,并继续作为十六进制数字和下划线的任何混合(至少一个数字)。
  • 八进制文字 以字符序列 U+0030 U+006F (0o) 开头,并继续作为八进制数字和下划线的任何混合(至少一个数字)。
  • 二进制文字 以字符序列 U+0030 U+0062 (0b) 开头,并继续作为二进制数字和下划线的任何混合(至少一个数字)。

与任何字面量一样,整数文字后面可以跟一个后缀(紧接着,没有任何空格),如上所述。后缀不能以 eE 开头,因为这将被解释为浮点数文字的指数。有关这些后缀的效果,请参阅 整数文字表达式

作为文字表达式被接受的整数文字示例

#![allow(unused)]
fn main() {
#![allow(overflowing_literals)]
123;
123i32;
123u32;
123_u32;

0xff;
0xff_u8;
0x01_f32; // integer 7986, not floating-point 1.0
0x01_e3;  // integer 483, not floating-point 1000.0

0o70;
0o70_i16;

0b1111_1111_1001_0000;
0b1111_1111_1001_0000i64;
0b________1;

0usize;

// These are too big for their type, but are accepted as literal expressions.
128_i8;
256_u8;

// This is an integer literal, accepted as a floating-point literal expression.
5f32;
}

请注意,例如 -1i8 被分析为两个 token:- 后跟 1i8

不作为文字表达式被接受的整数文字示例

#![allow(unused)]
fn main() {
#[cfg(FALSE)] {
0invalidSuffix;
123AFB43;
0b010a;
0xAB_CD_EF_GH;
0b1111_f32;
}
}

元组索引

词法分析器
TUPLE_INDEX
   INTEGER_LITERAL

元组索引用于引用 元组元组结构体元组变体 的字段。

元组索引直接与文字 token 进行比较。元组索引从 0 开始,每个后续索引以十进制值将值递增 1。因此,只有十进制值会匹配,并且该值不得有任何额外的 0 前缀字符。

#![allow(unused)]
fn main() {
let example = ("dog", "cat", "horse");
let dog = example.0;
let cat = example.1;
// The following examples are invalid.
let cat = example.01;  // ERROR no field named `01`
let horse = example.0b10;  // ERROR no field named `0b10`
}

注意:元组索引可能包含某些后缀,但这并非旨在有效,并且可能会在未来的版本中删除。有关更多信息,请参阅 https://github.com/rust-lang/rust/issues/60210

浮点数文字

词法分析器
FLOAT_LITERAL
      DEC_LITERAL . (不是紧跟 ., _ 或 XID_Start 字符)
   | 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 (.) 结尾。如果文字不包含指数,则后缀不能以 eE 开头。有关这些后缀的效果,请参阅 浮点数文字表达式

作为文字表达式被接受的浮点数文字示例

#![allow(unused)]
fn main() {
123.0f64;
0.1f64;
0.1f32;
12E+99_f64;
let x: f64 = 2.;
}

最后一个示例有所不同,因为它无法将后缀语法与以句点结尾的浮点数文字 token 一起使用。2.f64 会尝试在 2 上调用名为 f64 的方法。

请注意,例如 -1.0 被分析为两个 token:- 后跟 1.0

不作为文字表达式被接受的浮点数文字示例

#![allow(unused)]
fn main() {
#[cfg(FALSE)] {
2.0f80;
2e5f80;
2e5e6;
2.0e5e6;
1.3e10u64;
}
}

类似于数字文字的保留形式

词法分析器
RESERVED_NUMBER
      BIN_LITERAL [2-9​]
   | OCT_LITERAL [8-9​]
   | ( BIN_LITERAL | OCT_LITERAL | HEX_LITERAL ) .
         (不是紧跟 ., _ 或 XID_Start 字符)
   | ( BIN_LITERAL | OCT_LITERAL ) (e|E)
   | 0b _* 输入结束或不是 BIN_DIGIT
   | 0o _* 输入结束或不是 OCT_DIGIT
   | 0x _* 输入结束或不是 HEX_DIGIT
   | DEC_LITERAL ( . DEC_LITERAL)? (e|E) (+|-)? 输入结束或不是 DEC_DIGIT

以下类似于数字文字的词法形式是保留形式。由于它们可能引起歧义,因此它们被 tokenizer 拒绝,而不是被解释为单独的 token。

  • 一个没有后缀的二进制或八进制文字,后跟一个十进制数字,该数字超出其基数的范围,中间没有空格。
  • 一个没有后缀的二进制、八进制或十六进制文字,后跟一个句点字符(对句点后面的内容的限制与浮点数文字相同),中间没有空格。
  • 一个没有后缀的二进制或八进制文字,后跟字符 eE,中间没有空格。
  • 以基数前缀之一开头,但不是有效的二进制、八进制或十六进制文字(因为它不包含数字)的输入。
  • 具有浮点数文字形式但指数中没有数字的输入。

保留形式示例

#![allow(unused)]
fn main() {
0b0102;  // this is not `0b010` followed by `2`
0o1279;  // this is not `0o127` followed by `9`
0x80.0;  // this is not `0x80` followed by `.` and `0`
0b101e;  // this is not a suffixed literal, or `0b101` followed by `e`
0b;      // this is not an integer literal, or `0` followed by `b`
0b_;     // this is not an integer literal, or `0` followed by `b_`
2e;      // this is not a floating-point literal, or `2` followed by `e`
2.0e;    // this is not a floating-point literal, or `2.0` followed by `e`
2em;     // this is not a suffixed literal, or `2` followed by `em`
2.0em;   // this is not a suffixed literal, or `2.0` followed by `em`
}

生命周期和循环标签

词法分析器
LIFETIME_TOKEN
      ' IDENTIFIER_OR_KEYWORD (不是紧跟 '
   | '_ (不是紧跟 '
   | RAW_LIFETIME

LIFETIME_OR_LABEL
      ' NON_KEYWORD_IDENTIFIER (不是紧跟 '
   | RAW_LIFETIME

RAW_LIFETIME
   'r# IDENTIFIER_OR_KEYWORD 除了 crate, self, super, Self (不是紧跟 '

RESERVED_RAW_LIFETIME : 'r#_ (不是紧跟 '

生命周期参数和 循环标签 使用 LIFETIME_OR_LABEL token。任何 LIFETIME_TOKEN 都将被词法分析器接受,例如,可以在宏中使用。

原始生命周期类似于普通生命周期,但其标识符以 r# 为前缀。(请注意,r# 前缀不包含在实际生命周期中。)

与普通生命周期不同,原始生命周期可以是任何严格或保留关键字,但 RAW_LIFETIME 上面列出的关键字除外。

为了避免与 占位符生命周期 混淆,使用 RESERVED_RAW_LIFETIME token 'r#_ 是错误的。

版本差异:原始生命周期在 2021 版本或更高版本中被接受。在早期版本中,token 'r#lt 被词法分析为 'r # lt

标点符号

标点符号 token 在此处列出是为了完整性。它们的各个用法和含义在链接的页面中定义。

符号名称用法
+加号加法Trait BoundsMacro Kleene Matcher
-减号减法, 取反
*星号乘法, 解引用, 裸指针, 宏 Kleene 匹配器, Use 通配符
/斜杠除法
%百分号求余
^脱字符按位和逻辑异或
!按位和逻辑非, 宏调用, 内部属性, Never 类型, 负 impls
&按位和逻辑与, 借用, 引用, 引用模式
|按位和逻辑或, 闭包, match 中的模式, if let, 和 while let
&&与与惰性与, 借用, 引用, 引用模式
||或或惰性或, 闭包
<<左移左移, 嵌套泛型
>>右移右移, 嵌套泛型
+=加等于加法赋值
-=减等于减法赋值
*=乘等于乘法赋值
/=除等于除法赋值
%=百分号等于求余赋值
^=脱字符等于按位异或赋值
&=与等于按位与赋值
|=或等于按位或赋值
<<=左移等于左移赋值
>>=右移等于右移赋值, 嵌套泛型
=等于赋值, 属性, 各种类型定义
==等于等于等于
!=不等不等于
>大于大于, 泛型, 路径
<小于小于, 泛型, 路径
>=大于等于大于或等于, 泛型
<=小于等于小于或等于
@At子模式绑定
_下划线通配符模式, 推断类型, 常量中的未命名项, 外部 crate, use 声明, 和 解构赋值
.字段访问, 元组索引
..点点范围, 结构体表达式, 模式, 范围模式
...点点点可变参数函数, 范围模式
..=点点等于包含范围, 范围模式
,逗号各种分隔符
;分号各种项和语句的终止符, 数组类型
:冒号各种分隔符
::路径分隔符路径分隔符
->右箭头函数返回类型, 闭包返回类型, 函数指针类型
=>胖箭头Match 分支,
<-左箭头左箭头符号自 Rust 1.0 之前就已不再使用,但它仍然被视为单个标记
#井号属性
$美元符号
?问号问号运算符, 可能有大小, 宏 Kleene 匹配器
~波浪号波浪号运算符自 Rust 1.0 之前就已不再使用,但其标记可能仍被使用

分隔符

括号标点符号用于语法的各个部分。左括号必须始终与右括号配对。括号及其中的标记在 中被称为“标记树”。括号的三种类型是

括号类型
{ }花括号
[ ]方括号
( )圆括号

保留前缀

词法分析器 2021+
RESERVED_TOKEN_DOUBLE_QUOTE : ( IDENTIFIER_OR_KEYWORD 除了 bcrbrcr | _ ) "
RESERVED_TOKEN_SINGLE_QUOTE : ( IDENTIFIER_OR_KEYWORD 除了 b | _ ) '
RESERVED_TOKEN_POUND : ( IDENTIFIER_OR_KEYWORD 除了 rbrcr | _ ) #
RESERVED_TOKEN_LIFETIME : ' (IDENTIFIER_OR_KEYWORD 除了 r | _) #

一些词法形式被称为保留前缀,它们被保留供将来使用。

源输入在词法上会被解释为非原始标识符(或关键字或 _),紧随其后是 #'" 字符(没有中间的空白),这被识别为保留前缀。

请注意,原始标识符、原始字符串字面量和原始字节字符串字面量可能包含 # 字符,但不被解释为包含保留前缀。

类似地,原始字符串字面量、字节字面量、字节字符串字面量、原始字节字符串字面量、C 字符串字面量和原始 C 字符串字面量中使用的 rbbrccr 前缀不被解释为保留前缀。

源输入在词法上会被解释为非原始生命周期(或关键字或 _),紧随其后是 # 字符(没有中间的空白),这被识别为保留生命周期前缀。

版本差异:从 2021 版本开始,保留前缀被词法分析器报告为错误(特别是,它们不能传递给宏)。

在 2021 版本之前,保留前缀被词法分析器接受,并解释为多个标记(例如,一个标记用于标识符或关键字,后跟一个 # 标记)。

所有版本都接受的示例

#![allow(unused)]
fn main() {
macro_rules! lexes {($($_:tt)*) => {}}
lexes!{a #foo}
lexes!{continue 'foo}
lexes!{match "..." {}}
lexes!{r#let#foo}         // three tokens: 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}
}

保留 guard

词法分析器 2024+
RESERVED_GUARDED_STRING_LITERAL : #+ STRING_LITERAL
RESERVED_POUNDS : #2..

保留 guard 是为将来使用而保留的语法,如果使用将生成编译错误。

保留 guarded 字符串字面量是一个或多个 U+0023 (#) 紧随其后的 STRING_LITERAL 的标记。

保留 pounds 是两个或多个 U+0023 (#) 的标记。

版本差异:在 2024 版本之前,保留 guard 被词法分析器接受,并解释为多个标记。例如,#"foo"# 形式被解释为三个标记。## 被解释为两个标记。