Rust 书的模式部分中的匹配阴影示例非常令人困惑

  • 本文关键字:非常 模式部 Rust 阴影 rust
  • 更新时间 :
  • 英文 :


在学习 Rust 的过程中,我在官方 Rust 书中遇到了以下内容:

模式有一个陷阱:就像任何引入新模式的东西一样 绑定,它们引入了阴影。例如:

let x = 'x';
let c = 'c';
match c {
    x => println!("x: {} c: {}", x, c),
}
println!("x: {}", x)

这将打印:

x: c c: c
x: x

换句话说,x =>匹配模式并引入新的绑定 命名x,在火柴臂的范围内。因为我们已经有一个 绑定名为x,这个新x遮蔽了它。

我不明白两件事:

  1. 为什么比赛会成功?
    cx值的不同不应该导致这失败吗?
  2. 如何x绑定的匹配臂设置为'c'
    这在某种程度上是println!表达的回归吗?

match的内容存在根本性的误解。

顾名思义,模式匹配不是关于值的匹配,而是关于模式的匹配。为了方便和安全起见,它还允许将名称绑定到匹配模式的内部:

match some_option {
    Some(x) => println!("Some({})", x),
    None    => println!("None"),
}

为方便起见,match 在专门匹配文字(积分或布尔值)时扩展为匹配,我认为这是您混淆的根源。

为什么?因为match必须详尽无遗

match表达式的存在,因此编译器可以保证您处理所有可能性;检查您是否处理所有模式很容易,因为它们在编译器的控制之下,在存在自定义相等运算符的情况下检查您是否处理所有值是困难的。


在匹配子句中仅使用名称时,您将创建一个无可辩驳的模式:一种永远不会失败的模式。在这种情况下,要匹配的整个值将绑定到此名称。

您可以通过添加第二个匹配子句来展示这一点 之后,编译器将警告后一个绑定无法访问:

fn main() {
    let x = 42;
    match x {
        name => println!("{}", name),
        _    => println!("Other"),
    };
}
<anon>:6:5: 6:6 error: unreachable pattern [E0001]
<anon>:6         _    => println!("Other"),
                 ^

结合阴影规则(这些规则专门允许通过重用绑定名称来绑定另一个值来隐藏作用域中的绑定),您可以得到以下示例:

  • match臂内,x'c'的价值绑定
  • 在 arm 之后,范围内唯一的x是绑定到值的原始'x'

您的两点是由相同的根本问题引起的。巧合的是,本节存在的原因是指出您询问的问题!恐怕我基本上会用不同的词来反刍书上所说的内容。

查看此示例:

match some_variable {
    a_name => {},
}

在这种情况下,匹配臂将始终成功。无论some_variable中的值如何,它都将始终绑定到该匹配臂内的名称a_name。首先获取这部分很重要 — 绑定变量的名称与match之外的任何内容无关。

现在我们来看你的例子:

match c {
    x => println!("x: {} c: {}", x, c),
}

完全相同的逻辑适用。匹配臂始终匹配,无论c的值如何,它都将始终绑定到臂内的名称x

来自外部范围的x(在这种情况下'x')与模式匹配没有任何关系。


如果要使用 x 的值来控制模式匹配,可以使用匹配保护

match c {
    a if a == x => println!("yep"),
    _ => println!("nope"),
}

请注意,在匹配守卫 ( if a == x ) 中,变量绑定ax恢复为可以测试的普通变量。