impl 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);
この場合、2番目の引数式(&b
)のタイプはであることに注意してください&String
。次に、それがderef-coercedされ&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>>
何故ですか?私には、関数の候補が1つしかない場合にのみderef強制が行われるように見えます。しかし、これは私には間違っているようです。なぜルールはそのようになるのでしょうか?仕様を調べてみましたが、引数のderef強制で何も見つかりませんでした。
impl
、適用される特性が1つしかない場合は、その中で使用される型引数を選択することで明確化できimpl
ます。他のQ&Aでは、この機能を使用して、コンパイラー(見かけ上)impl
が呼び出しサイトでを選択するようにしました。これは、通常は実行できないことです。おそらくこの場合、それがderef強制を可能にするものです。しかし、それは推測にすぎません。