Ich bin auf dieses Problem gestoßen Add<char> for String
, als ich versucht habe, das Impl zur Standardbibliothek hinzuzufügen . Aber wir können es leicht replizieren, ohne Operator-Spielereien. Wir beginnen damit:
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
}
}
Einfach genug. Damit wird der folgende Code kompiliert:
let a = String::from("a");
let b = String::from("b");
MyAdd::add(a, &b);
Beachten Sie, dass in diesem Fall das zweite Argument expression ( &b
) den Typ hat &String
. Es wird dann deref-gezwungen &str
und der Funktionsaufruf funktioniert.
Versuchen wir jedoch , das folgende Impl hinzuzufügen:
impl MyAdd<char> for String {
fn add(mut self, rhs: char) -> Self {
self.push(rhs);
self
}
}
Der MyAdd::add(a, &b)
obige Ausdruck führt nun zu folgendem Fehler:
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>>
Warum ist das so? Mir scheint, dass Deref-Zwang nur dann ausgeübt wird, wenn es nur einen Funktionskandidaten gibt. Aber das scheint mir falsch zu sein. Warum sollten die Regeln so sein? Ich habe versucht, die Spezifikation durchzusehen, aber ich habe nichts über Argumentationszwang gefunden.
impl
zutrifft, kann er durch Auswahl des darin verwendeten Typarguments eindeutig unterscheidenimpl
. In den anderen Fragen und Antworten habe ich diese Fähigkeit verwendet, um den Compiler (anscheinend) dazu zu bringen, eineimpl
an der Aufrufstelle auszuwählen , was normalerweise nicht möglich ist. Vermutlich ist es in diesem Fall das, was es erlaubt, Zwang zu üben. Aber das ist nur eine Vermutung.