J'ai rencontré ce problème en essayant d'ajouter l'impl Add<char> for String
à la bibliothèque standard. Mais nous pouvons le reproduire facilement, sans manigances d'opérateur. Nous commençons par ceci:
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
}
}
Assez simple. Avec cela, le code suivant se compile:
let a = String::from("a");
let b = String::from("b");
MyAdd::add(a, &b);
Notez que dans ce cas, la seconde expression d'argument ( &b
) a le type &String
. Il est ensuite dé-contraint &str
et l'appel de fonction fonctionne.
Cependant , essayons d'ajouter l'impl suivant:
impl MyAdd<char> for String {
fn add(mut self, rhs: char) -> Self {
self.push(rhs);
self
}
}
Maintenant, l' MyAdd::add(a, &b)
expression ci-dessus conduit à l'erreur suivante:
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>>
Pourquoi donc? Il me semble que la deref-coercition ne se fait que lorsqu'il n'y a qu'une seule fonction candidate. Mais cela me semble faux. Pourquoi les règles seraient-elles ainsi? J'ai essayé de parcourir la spécification, mais je n'ai rien trouvé sur l'argument deref coercion.
impl
qui s'applique, il peut lever l'ambiguïté en choisissant l'argument type utilisé dans celaimpl
. Dans les autres questions et réponses, j'ai utilisé cette capacité pour que le compilateur (apparemment) choisisse unimpl
sur le site d'appel, ce qui n'est généralement pas possible. Vraisemblablement dans ce cas, c'est ce qui lui permet d'exercer une contrainte deref. Mais ce n'est qu'une supposition.