Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

词法单元

Syntax
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
    | FLOAT_LITERAL
    | INTEGER_LITERAL
    | LIFETIME_TOKEN
    | PUNCTUATION
    | IDENTIFIER_OR_KEYWORD

词法单元是语法格式中由正则(非递归)语言定义的原始生成式。Rust源输入可以分解为以下几种词法单元:

在此文档的语法中,“简单”词法单元以字符串表生成式形式给出,并以等宽字体显示。

字面量

字面量是字面量表达式中使用的词法单元。

示例

字符和字符串

示例# 数量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

ASCII转义

名称
\x417位字符码(恰好2个十六进制数字,最大0x7F)
\n换行
\r回车
\tTab键
\\反斜杠
\0空字符

字节转义

名称
\x7F8位字符码(恰好2个十六进制数字)
\n换行
\r回车
\tTab键
\\反斜杠
\0空字符

Unicode转义

名称
\u{7FFF}24位Unicode字符码(最多6个十六进制数字)

引号转义

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

数字

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

后缀

后缀是紧跟在字面量主要部分(无中间空白)后面的一串字符,其形式与非原始标识符关键字相同。

Syntax
SUFFIXIDENTIFIER_OR_KEYWORDexcept _

SUFFIX_NO_ESUFFIXnot beginning with e or E

SUFFIX_NO_E not beginning with `e` or `E` SUFFIX

任何类型的字面量(字符串、整数等)与任何后缀组合,都可作为有效的词法单元。

带有任何后缀的字面量词法单元可以传递给宏而不会产生错误。宏本身将决定如何解释此类词法单元以及是否产生错误。特别是,声明宏的literal fragment specifier匹配带有任意后缀的字面量词法单元。

#![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, isizef32, f64

字符和字符串字面量

字符字面量

Syntax
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..6valid hex char value }3

字符字面量是单个Unicode字符,用两个U+0027(单引号)字符括起来,但U+0027本身除外,它必须通过前面加一个U+005C字符(\)进行转义。

字符串字面量

Syntax
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+0078x)开头,后跟恰好两个十六进制数字,值最大为0x7F。它表示ASCII字符,其值等于提供的十六进制值。不允许更高的值,因为它们是Unicode码点还是字节值存在歧义。
  • 24位码点转义以U+0075u)开头,后跟最多六个十六进制数字,并用花括号U+007B{)和U+007D})括起来。它表示等于所提供十六进制值的Unicode码点。该值必须是有效的Unicode标量值。
  • 空白转义是字符U+006En)、U+0072r)或U+0074t)之一,分别表示Unicode值U+000A (LF)、U+000D (CR)或U+0009 (HT)。
  • 空转义是字符U+00300),表示Unicode值U+0000 (NUL)。
  • 反斜杠转义是字符U+005C\),它必须被转义才能表示自身。

原始字符串字面量

Syntax
RAW_STRING_LITERALr RAW_STRING_CONTENT SUFFIX?

RAW_STRING_CONTENT
      " ( ~CR )* (non-greedy) "
    | # RAW_STRING_CONTENT #

原始字符串字面量不处理任何转义。它们以字符U+0072r)开头,后跟少于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
}

字节和字节字符串字面量

字节字面量

Syntax
BYTE_LITERAL
    b' ( ASCII_FOR_CHAR | BYTE_ESCAPE ) ' SUFFIX?

ASCII_FOR_CHAR
    <any ASCII (i.e. 0x00 to 0x7F) except ', \, LF, CR, or TAB>

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

ASCII_FOR_CHAR any ASCII (i.e. 0x00 to 0x7F) except `'`, `\`, LF, CR, or TAB

字节字面量是一个单个ASCII字符(在U+0000U+007F范围内)或一个单个_转义_字符,前面带有字符U+0062b)和U+0027(单引号),后面带有字符U+0027。如果U+0027字符出现在字面量中,它必须通过前面加一个U+005C\)字符进行转义。它等同于一个u8无符号8位整数数字字面量。

字节字符串字面量

Syntax
BYTE_STRING_LITERAL
    b" ( ASCII_FOR_STRING | BYTE_ESCAPE | STRING_CONTINUE )* " SUFFIX?

ASCII_FOR_STRING
    <any ASCII (i.e 0x00 to 0x7F) except ", \, or CR>

非原始字节字符串字面量是一个ASCII字符和_转义_序列,前面带有字符U+0062b)和U+0022(双引号),后面带有字符U+0022。如果U+0022字符出现在字面量中,它必须通过前面加一个U+005C\)字符进行转义。另外,字节字符串字面量可以是下面定义的原始字节字符串字面量。

换行符(由字符U+000A (LF)表示)在字节字符串字面量中是允许的。字符U+000D (CR)不得出现在字节字符串字面量中。当未转义的U+005C字符(\)紧接在换行符之前时,换行符不会出现在词法单元所表示的字符串中。有关详细信息,请参阅字符串续行转义

在字节或非原始字节字符串字面量中,还有一些额外的_转义_可用。转义以U+005C\)开头,并接以下形式之一:

  • 字节转义以U+0078x)开头,后跟恰好两个十六进制数字。它表示等于所提供十六进制值的字节。
  • 空白转义是字符U+006En)、U+0072r)或U+0074t)之一,分别表示字节值0x0A (ASCII LF)、0x0D (ASCII CR)或0x09 (ASCII HT)。
  • 空转义是字符U+00300),表示字节值0x00 (ASCII NUL)。
  • 反斜杠转义是字符U+005C\),它必须被转义才能表示其ASCII编码0x5C

原始字节字符串字面量

Syntax
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
    <any ASCII (i.e. 0x00 to 0x7F) except CR>

原始字节字符串字面量不处理任何转义。它们以字符U+0062b)开头,后跟U+0072r),再后跟少于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字符串字面量

Syntax
C_STRING_LITERAL
    c" (
        ~[" \ CR NUL]
      | BYTE_ESCAPEexcept \0 or \x00
      | UNICODE_ESCAPEexcept \u{0}, \u{00}, …, \u{000000}
      | STRING_CONTINUE
    )* " SUFFIX?

C_STRING_LITERAL c" ⚠️ with the exception of " \ CR NUL CHAR except `\0` or `\x00` BYTE_ESCAPE except `\u{0}`, `\u{00}`, …, `\u{000000}` UNICODE_ESCAPE STRING_CONTINUE " SUFFIX

C字符串字面量是一个Unicode字符和_转义_序列,前面带有字符U+0063c)和U+0022(双引号),后面带有字符U+0022。如果U+0022字符出现在字面量中,它必须通过前面加一个U+005C\)字符进行转义。另外,C字符串字面量可以是下面定义的原始C字符串字面量。

C字符串隐式以字节0x00终止,因此C字符串字面量c""等同于手动从字节字符串字面量b"\x00"构造一个&CStr。除了隐式终止符,字节0x00不允许出现在C字符串中。

换行符(由字符U+000A (LF)表示)在C字符串字面量中是允许的。字符U+000D (CR)不得出现在C字符串字面量中。当未转义的U+005C字符(\)紧接在换行符之前时,换行符不会出现在词法单元所表示的字符串中。有关详细信息,请参阅字符串续行转义

在非原始C字符串字面量中,还有一些额外的_转义_可用。转义以U+005C\)开头,并接以下形式之一:

  • 字节转义以U+0078x)开头,后跟恰好两个十六进制数字。它表示等于所提供十六进制值的字节。
  • 24位码点转义以U+0075u)开头,后跟最多六个十六进制数字,并用花括号U+007B{)和U+007D})括起来。它表示等于所提供十六进制值的Unicode码点,以UTF-8编码。
  • 空白转义是字符U+006En)、U+0072r)或U+0074t)之一,分别表示字节值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";
}

2021 版次差异

C字符串字面量在2021或更高版次中被接受。在更早的版次中,词法单元c""被解析为c ""

原始C字符串字面量

Syntax
RAW_C_STRING_LITERAL
    cr RAW_C_STRING_CONTENT SUFFIX?

RAW_C_STRING_CONTENT
      " ( ~[CR NUL] )* (non-greedy) "
    | # RAW_C_STRING_CONTENT #

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

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

原始C字符串体中包含的所有字符都以UTF-8编码表示其本身。字符U+0022(双引号)(除非后面紧跟的U+0023#)字符数量与用于开始原始C字符串字面量的字符数量相同或更多)或U+005C\)不具有任何特殊含义。

2021 版次差异

原始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
}

数字字面量

数字字面量可以是整数字面量,也可以是浮点数字面量。识别这两种字面量的语法格式是混合的。

整数字面量

Syntax
INTEGER_LITERAL
    ( BIN_LITERAL | OCT_LITERAL | HEX_LITERAL | DEC_LITERAL ) SUFFIX_NO_E?

DEC_LITERALDEC_DIGIT ( DEC_DIGIT | _ )*

BIN_LITERAL0b _* BIN_DIGIT ( BIN_DIGIT | _ )*

OCT_LITERAL0o _* OCT_DIGIT ( OCT_DIGIT | _ )*

HEX_LITERAL0x _* 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+00780x)开头,并可包含十六进制数字和下划线的任意组合(至少包含一个数字)。
  • 八进制字面量以字符序列U+0030 U+006F0o)开头,并可包含八进制数字和下划线的任意组合(至少包含一个数字)。
  • 二进制字面量以字符序列U+0030 U+00620b)开头,并可包含二进制数字和下划线的任意组合(至少包含一个数字)。

像任何字面量一样,整数字面量可以紧跟(不带任何空格)一个如上所述的后缀。后缀不能以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被解析为两个词法单元:-后跟1i8

不被接受为字面量表达式的整数字面量示例:

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

元组索引

Syntax
TUPLE_INDEXDEC_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;
// The following examples are invalid.
let cat = example.01;  // ERROR no field named `01`
let horse = example.0b10;  // ERROR no field named `0b10`
let unicorn = example.0usize; // ERROR suffixes on a tuple index are invalid
let underscore = example.0_0; // ERROR no field `0_0` on type `(&str, &str, &str)`
}

浮点数字面量

Syntax
FLOAT_LITERAL
      DEC_LITERAL ( . DEC_LITERAL )? FLOAT_EXPONENT SUFFIX?
    | DEC_LITERAL . DEC_LITERAL SUFFIX_NO_E?
    | DEC_LITERAL .not immediately followed by ., _ or an XID_Start character

FLOAT_EXPONENT
    ( e | E ) ( + | - )? _* 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.;
}

最后一个示例有所不同,因为浮点数字面量以句点结尾时,无法使用后缀语法格式。2.f64会尝试在2上调用名为f64的方法。

请注意,例如-1.0被解析为两个词法单元:-后跟1.0

不被接受为字面量表达式的浮点数字面量示例:

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

类似于数字字面量的保留形式

Syntax
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>

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

以下类似于数字字面量的词法形式是_保留形式_。由于可能存在的歧义,词法分析器会拒绝这些形式,而不是将其解释为单独的词法单元。

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

保留形式的示例:

#![allow(unused)]
fn main() {
0b0102;  // 这不是`0b010`后跟`2`
0o1279;  // 这不是`0o127`后跟`9`
0x80.0;  // 这不是`0x80`后跟`.`和`0`
0b101e;  // 这不是一个带后缀的字面量,也不是`0b101`后跟`e`
0b;      // 这不是一个整数字面量,也不是`0`后跟`b`
0b_;     // 这不是一个整数字面量,也不是`0`后跟`b_`
2e;      // 这不是一个浮点数字面量,也不是`2`后跟`e`
2.0e;    // 这不是一个浮点数字面量,也不是`2.0`后跟`e`
2em;     // 这不是一个带后缀的字面量,也不是`2`后跟`em`
2.0em;   // 这不是一个带后缀的字面量,也不是`2.0`后跟`em`
}

生命周期和循环标签

Syntax
LIFETIME_TOKEN
      RAW_LIFETIME
    | ' IDENTIFIER_OR_KEYWORDnot immediately followed by '

LIFETIME_OR_LABEL
      RAW_LIFETIME
    | ' NON_KEYWORD_IDENTIFIERnot immediately followed by '

RAW_LIFETIME
    'r# IDENTIFIER_OR_KEYWORDnot immediately followed by '

RESERVED_RAW_LIFETIME'r# ( _ | crate | self | Self | super )not immediately followed by '

RAW_LIFETIME 'r# not immediately followed by `'` IDENTIFIER_OR_KEYWORD
RESERVED_RAW_LIFETIME 'r# not immediately followed by `'` _ crate self Self super

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

原始生命周期类似于普通生命周期,但其标识符带有r#前缀。(请注意,r#前缀不作为实际生命周期的一部分。)

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

使用RESERVED_RAW_LIFETIME词法单元是错误的。

2021 版次差异

原始生命周期在2021或更高版次中被接受。在更早的版次中,词法单元'r#lt被解析为'r # lt

标点符号

标点符号词法单元用作运算符、分隔符和语法格式的其他部分。

Syntax
PUNCTUATION
      ...
    | ..=
    | <<=
    | >>=
    | !=
    | %=
    | &&
    | &=
    | *=
    | +=
    | -=
    | ->
    | ..
    | /=
    | ::
    | <-
    | <<
    | <=
    | ==
    | =>
    | >=
    | >>
    | >
    | ^=
    | |=
    | ||
    | !
    | #
    | $
    | %
    | &
    | (
    | )
    | *
    | +
    | ,
    | -
    | .
    | /
    | :
    | ;
    | <
    | =
    | ?
    | @
    | [
    | ]
    | ^
    | {
    | |
    | }
    | ~

PUNCTUATION ... ..= <<= >>= != %= && &= *= += -= -> .. /= :: <- << <= == => >= >> > ^= |= || ! # $ % & ( ) * + , - . / : ; < = ? @ [ ] ^ { | } ~

注意

有关标点符号字符如何使用的链接,请参阅语法格式索引

分隔符

括号标点符号用于语法格式的各个部分。开括号必须始终与闭括号配对。括号及其内部的词法单元在中被称为“词法单元树”。括号有三种类型:

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

保留词法单元

几种词法单元形式被保留以备将来使用或避免混淆。源输入匹配其中一种形式是错误的。

保留前缀

Syntax
RESERVED_TOKEN_DOUBLE_QUOTE
    IDENTIFIER_OR_KEYWORDexcept b or c or r or br or cr "

RESERVED_TOKEN_SINGLE_QUOTE
    IDENTIFIER_OR_KEYWORDexcept b '

RESERVED_TOKEN_POUND
    IDENTIFIER_OR_KEYWORDexcept r or br or cr #

RESERVED_TOKEN_LIFETIME
    ' IDENTIFIER_OR_KEYWORDexcept r #

一些被称为_保留前缀_的词法形式被保留以备将来使用。

源输入如果被词法解释为非原始标识符(或关键字),且紧跟#'"字符(无中间空白),则被识别为保留前缀。

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

同样,用于原始字符串字面量、字节字面量、字节字符串字面量、原始字节字符串字面量、C字符串字面量和原始C字符串字面量的rbbrccr前缀不被解释为保留前缀。

源输入如果被词法解释为非原始生命周期(或关键字),且紧跟#字符(无中间空白),则被识别为保留生命周期前缀。

2021 版次差异

从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}
}

保留的守卫

Syntax
RESERVED_GUARDED_STRING_LITERAL#+ STRING_LITERAL

RESERVED_POUNDS#2..

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

保留的带守卫字符串字面量是一个词法单元,由一个或多个U+0023#)紧接着一个STRING_LITERAL组成。

保留的井号是一个由两个或更多U+0023#)组成的词法单元。

2024 版次差异

在2024版次之前,词法分析器会接受保留的守卫,并将其解释为多个词法单元。例如,#"foo"#形式被解释为三个词法单元。##被解释为两个词法单元。


  1. 相同字面量两侧#的数量必须相等。

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

  3. 参阅lex.token.literal.char-escape.unicode