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.
quelle
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.Antworten:
Wie Sie selbst erklärt haben, behandelt der Compiler den Fall, in dem nur einer
impl
speziell gültig ist , und kann diesen verwenden, um die Typinferenz zu steuern:Der zweite Teil ist, dass Deref-Zwang nur an Orten auftritt , an denen der erwartete Typ bekannt ist, nicht spekulativ. Siehe Zwangsstellen in der Referenz. Impl Auswahl und Typinferenz müssen zuerst explizit herausfinden,
MyAdd::add(&str)
was zu erwarten wäre, um zu versuchen, das Argument zu erzwingen&str
.Wenn in dieser Situation eine Problemumgehung erforderlich ist, verwenden Sie einen Ausdruck wie
&*b
oder&b[..]
oderb.as_str()
für das zweite Argument.quelle