字面量表达式

语法
LiteralExpression :
      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
   | true | false

字面量表达式是由单个词法单元(token)组成的表达式,而不是由词法单元序列组成。它直接且立即地表示它求值后的值,而不是通过名称或其他求值规则来引用它。

字面量是 常量表达式 的一种形式,因此(主要)在编译时求值。

如前所述的每个词法 字面量 形式都可以构成一个字面量表达式,关键字 truefalse 也是如此。

#![allow(unused)]
fn main() {
"hello";   // string type
'5';       // character type
5;         // integer type
}

在下面的描述中,词法单元的字符串表示是从输入中匹配词法分析器(Lexer)语法片段中词法单元产生式的字符序列。

注意:此字符串表示永远不包含紧随 U+000D (CR) 之后的 U+000A (LF) 字符:这对字符之前会被转换为单个 U+000A (LF)。

转义符

以下文本字面量表达式的描述使用了几种形式的转义

每种形式的转义都以以下特征为特征:

  • 转义序列:一个字符序列,总是以 U+005C (\) 开头
  • 转义值:可以是单个字符或一个空字符序列

在以下转义符的定义中:

  • 八进制数字是范围 [0-7] 中的任何字符。
  • 十六进制数字是范围 [0-9]、[a-f] 或 [A-F] 中的任何字符。

简单转义符

下表第一列中出现的每个字符序列都是一个转义序列。

在每种情况下,转义值是第二列中相应条目中给出的字符。

转义序列转义值
\0\0
U+0000 (NUL)\t
U+0009 (HT)\n
U+000A (LF)\r
\"U+000D (CR)
\'\"
\\U+0022 (QUOTATION MARK)

\'

U+0027 (APOSTROPHE)

\\

U+005C (REVERSE SOLIDUS)

8 位转义符

转义序列由 \x 后跟两个十六进制数字组成。

\\

转义值是字符,其 Unicode 标量值 是将转义序列中最后两个字符解释为十六进制整数的结果,如同通过使用基数 16 的 u8::from_str_radix

注意:因此,转义值具有 Unicode 标量值,其范围在 u8 的范围内。

7 位转义符

转义序列由 \x 后跟一个八进制数字,然后是一个十六进制数字组成。

Unicode 转义符

转义序列由 \u{ 开头,后跟一个字符序列,每个字符都是十六进制数字或 _,然后是 }

转义值是字符,其 Unicode 标量值 是将转义序列中包含的十六进制数字解释为十六进制整数的结果,如同通过使用基数 16 的 u32::from_str_radix

注意CHAR_LITERALSTRING_LITERAL 词法单元的允许形式确保存在这样的字符。

#![allow(unused)]
fn main() {
let a = "foobar";
let b = "foo\
         bar";
let c = "foo\

     bar";

assert_eq!(a, b);
assert_eq!(b, c);
}

字符串延续转义符

转义序列由 \ 后紧跟 U+000A (LF) 以及下一个非空白字符之前的所有后续空白字符组成。为此,空白字符是 U+0009 (HT)、U+000A (LF)、U+000D (CR) 和 U+0020 (SPACE)。

转义值是一个空字符序列。

注意:这种形式的转义的效果是字符串延续会跳过后续的空白字符,包括额外的换行符。因此,abc 是相等的:

跳过额外的换行符(如示例 c 中所示)可能会令人困惑和意外。此行为将来可能会进行调整。在做出决定之前,建议避免依赖于使用行延续来跳过多个换行符。有关更多信息,请参阅 此问题

字符字面量表达式

字符字面量表达式由单个 CHAR_LITERAL 词法单元组成。

词法单元的字面内容是词法单元的字符串表示中,第一个 U+0027 (') 之后和最后一个 U+0027 (') 之前的字符序列。

字面量表达式的表示字符从字面内容派生,如下所示:

如果字面内容是以下形式的转义序列之一,则表示字符是转义序列的转义值:

#![allow(unused)]
fn main() {
'R';                               // R
'\'';                              // '
'\x52';                            // R
'\u{00E6}';                        // LATIN SMALL LETTER AE (U+00E6)
}

否则,表示字符是构成字面内容的单个字符。

表达式的值是与表示字符的 Unicode 标量值 相对应的 char

注意CHAR_LITERAL 词法单元的允许形式确保这些规则始终产生单个字符。

跳过额外的换行符(如示例 c 中所示)可能会令人困惑和意外。此行为将来可能会进行调整。在做出决定之前,建议避免依赖于使用行延续来跳过多个换行符。有关更多信息,请参阅 此问题

字符字面量表达式的示例:

字符串字面量表达式

字面量表达式的表示字符串是从字面内容派生出的字符序列,如下所示:

如果词法单元是 STRING_LITERAL,则字面内容中出现的以下形式的每个转义序列都将被转义序列的转义值替换。

#![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
}

这些替换以从左到右的顺序进行。例如,词法单元 "\\x41" 将转换为字符 \ x 4 1

如果词法单元是 RAW_STRING_LITERAL,则表示字符串与字面内容相同。

表达式的值是对静态分配的 str 的引用,其中包含表示字符串的 UTF-8 编码。

跳过额外的换行符(如示例 c 中所示)可能会令人困惑和意外。此行为将来可能会进行调整。在做出决定之前,建议避免依赖于使用行延续来跳过多个换行符。有关更多信息,请参阅 此问题

字符字面量表达式

字符字面量表达式由单个 CHAR_LITERAL 词法单元组成。

字符串字面量表达式的示例:

字节字面量表达式

字节字面量表达式由单个 BYTE_LITERAL 词法单元组成。

#![allow(unused)]
fn main() {
b'R';                              // 82
b'\'';                             // 39
b'\x52';                           // 82
b'\xA0';                           // 160
}

表达式的类型是原始的 u8 类型。

表达式的值是表示字符的 Unicode 标量值

注意BYTE_LITERAL 词法单元的允许形式确保这些规则始终产生单个字符,其 Unicode 标量值在 u8 的范围内。

跳过额外的换行符(如示例 c 中所示)可能会令人困惑和意外。此行为将来可能会进行调整。在做出决定之前,建议避免依赖于使用行延续来跳过多个换行符。有关更多信息,请参阅 此问题

字符字面量表达式的示例:

字符串字面量表达式

表达式的类型是对数组的共享引用(具有 static 生命周期),该数组的元素类型是 u8。也就是说,类型为 &'static [u8; N],其中 N 是下面描述的表示字符串中的字节数。

如果词法单元是 BYTE_STRING_LITERAL,则字面内容中出现的以下形式的每个转义序列都将被转义序列的转义值替换。

这些替换以从左到右的顺序进行。例如,词法单元 b"\\x41" 将转换为字符 \ x 4 1

#![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
}

如果词法单元是 RAW_BYTE_STRING_LITERAL,则表示字符串与字面内容相同。

表达式的值是对静态分配的数组的引用,该数组包含表示字符串中字符的 Unicode 标量值,顺序相同。

注意BYTE_STRING_LITERALRAW_BYTE_STRING_LITERAL 词法单元的允许形式确保这些规则始终产生在 u8 范围内的数组元素值。

跳过额外的换行符(如示例 c 中所示)可能会令人困惑和意外。此行为将来可能会进行调整。在做出决定之前,建议避免依赖于使用行延续来跳过多个换行符。有关更多信息,请参阅 此问题

字节字符串字面量表达式的示例:

C 字符串字面量表达式

  • C 字符串字面量表达式由单个 C_STRING_LITERALRAW_C_STRING_LITERAL 词法单元组成。

    • 表达式的类型是对标准库 CStr 类型的共享引用(具有 static 生命周期)。也就是说,类型为 &'static core::ffi::CStr
    • 词法单元的字面内容是词法单元的字符串表示中,第一个 " 之后和最后一个 " 之前的字符序列。
    • 字面量表达式的表示字节是从字面内容派生出的字节序列,如下所示:
    • 如果词法单元是 C_STRING_LITERAL,则字面内容被视为项的序列,每个项要么是除 \ 之外的单个 Unicode 字符,要么是 转义符。项的序列转换为字节序列,如下所示:
    • 每个单个 Unicode 字符贡献其 UTF-8 表示形式。
  • 每个 简单转义符 贡献其转义值的 Unicode 标量值

每个 8 位转义符 贡献一个字节,其中包含其转义值的 Unicode 标量值

每个 unicode 转义符 贡献其转义值的 UTF-8 表示形式。

每个 字符串延续转义符 不贡献任何字节。

#![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

c"æ";                                // LATIN SMALL LETTER AE (U+00E6)
c"\u{00E6}";                         // LATIN SMALL LETTER AE (U+00E6)
c"\xC3\xA6";                         // LATIN SMALL LETTER AE (U+00E6)

c"\xE6".to_bytes();                  // [230]
c"\u{00E6}".to_bytes();              // [195, 166]
}

如果词法单元是 RAW_C_STRING_LITERAL,则表示字节是字面内容的 UTF-8 编码。

注意C_STRING_LITERALRAW_C_STRING_LITERAL 词法单元的允许形式确保表示字节永远不包含空字节。

表达式的值是对静态分配的 CStr 的引用,其字节数组包含表示字节,后跟一个空字节。

C 字符串字面量表达式的示例:

  • 整数字面量表达式

  • 整数字面量表达式由单个 INTEGER_LITERAL 词法单元组成。

  • 如果词法单元带有 后缀,则后缀必须是 原始整数类型 之一的名称:u8i8u16i16u32i32u64i64u128i128usizeisize,并且表达式具有该类型。

如果词法单元没有后缀,则表达式的类型由类型推断确定:

#![allow(unused)]
fn main() {
123;                               // type i32
123i32;                            // type i32
123u32;                            // type u32
123_u32;                           // type u32
let a: u64 = 123;                  // type u64

0xff;                              // type i32
0xff_u8;                           // type u8

0o70;                              // type i32
0o70_i16;                          // type i16

0b1111_1111_1001_0000;             // type i32
0b1111_1111_1001_0000i64;          // type i64

0usize;                            // type usize
}

如果可以从周围的程序上下文中唯一确定整数类型,则表达式具有该类型。

  • 如果程序上下文对类型约束不足,则默认类型为有符号 32 位整数 i32

    • 如果程序上下文对类型约束过度,则会将其视为静态类型错误。
    • 整数字面量表达式的示例:
    • 表达式的值由词法单元的字符串表示确定,如下所示:
    • 通过检查字符串的前两个字符来选择整数基数,如下所示:
  • 0b 表示基数 2

  • 0o 表示基数 8

  • 0x 表示基数 16

  • 否则,基数为 10。

  • 如果基数不是 10,则从字符串中删除前两个字符。

从字符串中删除任何后缀。

从字符串中删除任何下划线。

字符串将转换为 u128 值,如同通过使用所选基数的 u128::from_str_radix。如果该值不适合 u128,则会发生编译器错误。

u128 值通过 数值转换 转换为表达式的类型。

  • 注意:如果字面量的值不适合表达式的类型,则最终的转换将截断该值。 rustc 包含一个名为 overflowing_literalslint 检查,默认设置为 deny,它会拒绝发生这种情况的表达式。
  • 注意:例如,-1i8 是将 取反运算符 应用于字面量表达式 1i8,而不是单个整数字面量表达式。有关表示有符号类型的最负值的说明,请参阅 溢出

浮点字面量表达式

C 字符串字面量表达式的示例:

  • 浮点字面量表达式具有以下两种形式之一:

  • 单个 FLOAT_LITERAL 词法单元

  • 如果词法单元带有 后缀,则后缀必须是 原始整数类型 之一的名称:u8i8u16i16u32i32u64i64u128i128usizeisize,并且表达式具有该类型。

带有后缀且没有基数指示符的单个 INTEGER_LITERAL 词法单元

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

如果可以从周围的程序上下文中唯一确定整数类型,则表达式具有该类型。

  • 0o 表示基数 8

  • 0x 表示基数 16

  • 如果词法单元带有 后缀,则后缀必须是 原始浮点类型 之一的名称:f32f64,并且表达式具有该类型。

如果可以从周围的程序上下文中唯一确定浮点类型,则表达式具有该类型。

如果程序上下文对类型约束不足,则默认类型为 f64

浮点字面量表达式的示例:

字符串将转换为表达式的类型,如同通过 f32::from_strf64::from_str

注意:例如,-1.0 是将 取反运算符 应用于字面量表达式 1.0,而不是单个浮点字面量表达式。

  • 注意infNaN 不是字面量词法单元。可以使用 f32::INFINITYf64::INFINITYf32::NANf64::NAN 常量来代替字面量表达式。在 rustc 中,如果字面量足够大以致于被求值为无穷大,则会触发 overflowing_literals lint 检查。
  • 布尔字面量表达式