为什么 match 语句对引用类型比函数参数更挑剔?

Why are match statements more picky about reference types than function parameters?

提问人:Smarwell 提问时间:2/7/2023 更新时间:2/7/2023 访问量:81

问:

在 Rust 中,人们经常看到作为参数的函数。&str

fn foo(bar: &str) {
    println!("{}", bar);
}

在调用这样的函数时,通过引用它来传入 a 作为参数是完全可以的。String

let bar = String::from("bar");
foo(&bar);

严格来说,传递的参数是 an,函数期待 ,但 Rust(正如人们所希望的那样)只是弄清楚了它,一切正常。但是,匹配语句并非如此。如果我尝试在 match 语句中使用与之前相同的变量,则不会编译朴素用法:&String&strbar

match &bar {
    "foo" => println!("foo"),
    "bar" => println!("bar"),
    _ => println!("Something else")
};

Rustc 抱怨说,它本来期待一个,但收到了一个 .问题和解决方案都非常明显:只需更明确地借用 .但这让我想到了一个真正的问题:为什么会这样?&str&Stringbar.as_str()

如果 Rust 可以弄清楚在函数参数的情况下,an 很容易转换为 an,为什么它不能对 match 语句做同样的事情呢?这是类型系统限制的结果,还是使用匹配语句进行更高级的借用存在隐藏的不安全因素?或者这仅仅是生活质量改善被整合到某些地方而不是其他地方的情况?我相信熟悉类型系统的人会给出答案,但互联网上关于这种行为怪癖的信息似乎很少。&String&str

rust 引用 匹配 借用

评论

1赞 PitaJ 2/7/2023
这称为“deref coercion”——可以取消引用到 an 中,编译器会在预期 时自动为您执行此操作。您描述的实际问题可能只是编译器的限制。&String&str&str

答:

5赞 kmdreko 2/7/2023 #1

它不起作用的技术原因是因为审查者不是胁迫网站。函数参数(如示例中所示)是可能的强制站点;它允许您因为胁迫而将 A 作为 A 传递。matchfoo(&bar)&String&strDeref

它不是胁迫网站的一个可能原因是,没有明确的类型应该胁迫它。在您的示例中,您希望它与字符串文字匹配,但是:&str

match &string_to_inspect {
    "special" => println!("this is a special string"),
    other => println!("this is a string with capacity: {}", other.capacity()),
};

人们希望表现得像与字面相匹配,但因为匹配是在一个上,所以人们也希望是一个。如何同时满足两者?下一个合乎逻辑的步骤是让每个模式根据需要强制执行,这是非常需要的......但它打开了一整罐蠕虫,因为它是用户可定义的。有关更多信息,请参阅 Rust lang-team 的 deref 模式match&str&Stringother&StringDeref

0赞 Solomon Ucko 2/7/2023 #2

https://doc.rust-lang.org/reference/type-coercions.html 说道:

胁迫网站

胁迫只能发生在程序中的某些胁迫地点;这些位置通常是所需类型显式或可以通过从显式类型传播(无需类型推断)派生的位置。可能的胁迫地点是:

  • [...]

  • 函数调用的参数

    被强制的值是实际参数,它被强制为形式参数的类型。

但不是审查者。match

胁迫类型

允许在以下类型之间进行胁迫:

  • [...]
  • &T或者 if implements .&mut T&UTDeref<Target = U>