当我试图将Add<char> for String
添加到标准库时,我遇到了这个问题。但是我们可以轻松地复制它,而不需要操作符的花招。我们从这个开始:
trait MyAdd<Rhs> {
fn add(self, rhs: Rhs) -> Self;
}
impl MyAdd<&str> for String {
fn add(mut self, rhs: &str) -> Self {
self.push_str(rhs);
self
}
}
很简单。使用此方法,以下代码将被编译:
let a = String::from("a");
let b = String::from("b");
MyAdd::add(a, &b);
请注意,在本例中,第二个参数表达式 (&b
) 的类型是 &String
。然后将其解引用强制转换为 &str
并使函数调用工作。
然而,让我们尝试添加以下实现:
impl MyAdd<char> for String {
fn add(mut self, rhs: char) -> Self {
self.push(rhs);
self
}
}
现在,上面的 MyAdd::add(a, &b)
表达式会导致以下错误:
error[E0277]: the trait bound `std::string::String: MyAdd<&std::string::String>` is not satisfied
--> src/main.rs:24:5
|
2 | fn add(self, rhs: Rhs) -> Self;
| ------------------------------- required by `MyAdd::add`
...
24 | MyAdd::add(a, &b);
| ^^^^^^^^^^ the trait `MyAdd<&std::string::String>` is not implemented for `std::string::String`
|
= help: the following implementations were found:
<std::string::String as MyAdd<&str>>
<std::string::String as MyAdd<char>>
为什么会这样? 在我看来,当只有一个函数候选时才会进行deref-coercion。但是这似乎是错误的。为什么规则会是这样呢?我试图查看规范文件,但我没有找到有关参数deref coercion的内容。
impl
时,它可以通过选择在该impl
中使用的类型参数来消除歧义。在另一个问题和答案中,我利用了这种能力,使编译器(表面上)在调用站点选择一个impl
,这是它通常无法做到的。大概在这种情况下,这就是允许它进行解引用强制转换的原因。但这只是一个猜测。 - trent