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

Sma*_*ell 3 reference match rust borrow

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

fn foo(bar: &str) {
    println!("{}", bar);
}
Run Code Online (Sandbox Code Playgroud)

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

let bar = String::from("bar");
foo(&bar);
Run Code Online (Sandbox Code Playgroud)

严格来说,传递的参数是 an&String并且函数期望是 an &str,但是 Rust(正如人们所希望的那样)只是计算出来并且一切正常。然而,match 语句的情况并非如此。bar如果我尝试在匹配语句中使用与之前相同的变量,则天真的用法将无法编译:

match &bar {
    "foo" => println!("foo"),
    "bar" => println!("bar"),
    _ => println!("Something else")
};
Run Code Online (Sandbox Code Playgroud)

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

如果 Rust 能够发现在函数参数的情况下an&String可以简单地转换为 an ,为什么它不能用 match 语句做同样的事情呢?&str这是类型系统限制的结果,还是使用 match 语句进行更奇特的借用是否存在隐藏的不安全性?或者这只是生活质量改善融入某些地方而不是其他地方的一个例子?我确信了解类型系统的人有答案,但互联网上关于这种行为小怪癖的信息似乎很少。

kmd*_*eko 5

它不起作用的技术原因是因为match审查者不是强制站点。如您的示例所示foo(&bar),函数参数可能是强制转换站点;并且它允许您由于强制而将 a&String作为 a传递。&strDeref

它不是强制站点的一个可能原因是没有明确的类型应该被强制。在您的示例中,您希望它是这样的,&str因为它与字符串文字匹配,但是怎么样:

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

人们希望 的match行为就像&str与文字相匹配,但因为匹配是在 a 上,所以人们也&String希望other是 a 。&String怎样才能同时满足呢?下一个合乎逻辑的步骤是让每个模式根据需要进行强制,这是人们非常希望的……但它会打开一整罐蠕虫,因为它Deref是用户可定义的。有关更多信息,请参阅Rust 语言团队的deref 模式。