2番目のimplを追加すると、なぜ引数のderef強制が妨げられるのですか?


10

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強制を可能にするものです。しかし、それは推測にすぎません。
trentcl

2
ここにコメントが1つだけ見つかった場合、コンパイラーはそれを「熱心に確認」して、(特に)deref強制が発生することを許可することを示しています。これは、複数の候補候補では発生しません。ですから、そういう答えだと思いますが、もっと知りたいと思っています。rustcブックのこの章は役立つかもしれませんが、私の知る限り、特にこれについて何かを述べているわけではありません。
Lukas Kalbertodt

回答:


0

あなた自身が説明したように、コンパイラは有効なものが1つしかない場合をimpl特別に扱い、これを使用して型推論を推進できます。

ここにコメントが1つだけ見つかった場合、コンパイラーはそれを「熱心に確認」します。これにより、(特に)deref強制が発生します。これは、複数の候補候補では発生しません。

2番目の部分は、期待どおりの型が既知であるサイトでのみderef強制が発生することであり、投機的には発生しません。参照してください強制サイト参照中に。Implの選択と型の推論では、最初に、それMyAdd::add(&str)が予期されるものであることを明示的に見つけて、引数をに強制しようとする必要があります&str

回避策は、このような状況で必要とされている場合は、のような表現を使用する&*bか、&b[..]またはb.as_str()第二引数のために。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.