İkinci bir impl eklemek neden argümanın kayıttan kaldırılmasını engelliyor?


10

Impl'yi Add<char> for Stringstandart kütüphaneye eklemeye çalışırken bu sorunla karşılaştım . Ancak operatör maskaralıkları olmadan kolayca çoğaltabiliriz. Bununla başlıyoruz:

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
    }
}

Yeterince basit. Bununla, aşağıdaki kod derlenir:

let a = String::from("a");
let b = String::from("b");
MyAdd::add(a, &b);

Bu durumda, ikinci bağımsız değişken ifadesinin ( &b) türüne sahip olduğunu unutmayın &String. Sonra deref zorlanır &strve işlev çağrısı çalışır.

Ancak , aşağıdaki implleri eklemeyi deneyelim:

impl MyAdd<char> for String {
    fn add(mut self, rhs: char) -> Self {
        self.push(rhs);
        self
    }
}

( Oyun Alanındaki Her Şey )

Şimdi MyAdd::add(a, &b)yukarıdaki ifade aşağıdaki hataya yol açar:

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>>

Neden? Bana göre deref-zorlama sadece bir işlev adayı olduğunda yapılıyor gibi görünüyor. Ama bu benim için yanlış görünüyor. Kurallar neden böyle olsun ki? Şartnameye bakmayı denedim, ama deref zorlama argümanı hakkında hiçbir şey bulamadım.


Bu bana bu cevabı hatırlatıyor (yazdım). Derleyici özelliği genel olarak bilir ve sadece bir tane olduğundaimpl geçerli olduğunda, bu türde kullanılan tür bağımsız değişkenini seçerek belirsizleşebilir impl. Diğer Soru-Cevap bölümünde, bu yeteneği derleyicinin implarama sitesinde bir seçim yapmak (görünüşe göre) yapmak için kullandım , ki bu genellikle yapamayacağı bir şeydir. Muhtemelen bu durumda deref zorlaması yapmasına izin veren şey budur. Ama bu sadece bir tahmin.
trentcl

2
İşte bir yorum sadece bir impl bulunursa derleyicinin bunu "hevesle onayladığını" belirten ve deref baskılarının (diğer şeylerin yanı sıra) gerçekleşmesine izin veren bulunmaktadır. Birden fazla impl adayı için bu gerçekleşmez. Sanırım bu bir cevap, ama daha fazlasını bilmek isterdim. Rustc kitabındaki bu bölüm yardımcı olabilir, ancak anlayabildiğim kadarıyla, bu konuda özel bir şey söylemiyor.
Lukas Kalbertodt

Yanıtlar:


0

Sizin açıkladığınız gibi, derleyici implözel olarak yalnızca bir tanesinin geçerli olduğu durumu ele alır ve bunu tür çıkarımını artırmak için kullanabilir:

Burada, yalnızca bir impl bulunursa derleyicinin "hevesle onayladığını" belirten ve deref baskılarının (diğer şeylerin yanı sıra) gerçekleşmesine izin veren bir yorum bulunmaktadır. Birden fazla impl adayı için bu gerçekleşmez.

İkinci bölüm deref baskısının sadece beklenen türün bilindiği yerlerde gerçekleşeceği, spekülatif olarak gerçekleşmeyeceğidir. Referanstaki baskı sitelerine bakın . Impl seçimi ve tür kesmesi gerekir ilk açıkça bulmak MyAdd::add(&str)için argüman zorlamak denemek için, beklenen &str.

Bu durumda bir geçici çözüm gerekiyorsa, aşağıdaki gibi bir ifade kullanın &*b veya &b[..]veya b.as_str()ikinci argüman için.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.