SORU
14 ŞUBAT 2015, CUMARTESİ


Pas'tam otomatik-kaldırma kuralları ne?

/Pas deneme öğreniyorum ve bu dilde bulduğum tüm zerafeti, beni şaşırtan bir özelliği olduğunu ve yersiz görünüyor tamamen.

Pas yöntem çağrıları yaparken otomatik olarak işaretçi çözümlemesi. Bazı testler kesin davranışlarını belirlemek için yaptım:

struct X { val: i32 }
impl std::ops::Deref for X {
    type Target = i32;
    fn deref(&self) -> &i32 { &self.val }
}


trait            M                   { fn m(self); }
impl             M for i32           { fn m(self) { println!("i32::m()"); } }
impl             M for X             { fn m(self) { println!("X::m()"); } }
impl<'a>         M for &'a X         { fn m(self) { println!("&X::m()"); } }
impl<'a, 'b>     M for &'a &'b X     { fn m(self) { println!("&&X::m()"); } }
impl<'a, 'b, 'c> M for &'a &'b &'c X { fn m(self) { println!("&&&X::m()"); } }

trait            RefM                   { fn refm(&self); }
impl             RefM for i32           { fn refm(&self) { println!("i32::refm()"); } }
impl             RefM for X             { fn refm(&self) { println!("X::refm()"); } }
impl<'a>         RefM for &'a X         { fn refm(&self) { println!("&X::refm()"); } }
impl<'a, 'b>     RefM for &'a &'b X     { fn refm(&self) { println!("&&X::refm()"); } }
impl<'a, 'b, 'c> RefM for &'a &'b &'c X { fn refm(&self) { println!("&&&X::refm()"); } }

struct Y { val: i32 }
impl std::ops::Deref for Y {
    type Target = i32;
    fn deref(&self) -> &i32 { &self.val }
}

struct Z { val: Y }
impl std::ops::Deref for Z {
    type Target = Y;
    fn deref(&self) -> &Y { &self.val }
}

struct A;
impl std::marker::Copy for A {}
impl             M for             A { fn m(self) { println!("A::m()"); } }
impl<'a, 'b, 'c> M for &'a &'b &'c A { fn m(self) { println!("&&&A::m()"); } }
impl             RefM for             A { fn refm(&self) { println!("A::refm()"); } }
impl<'a, 'b, 'c> RefM for &'a &'b &'c A { fn refm(&self) { println!("&&&A::refm()"); } }

fn main() {
    // I'll use @ to denote left side of the dot operator
    (*X{val:42}).m();        // i32::refm() , self == @
    X{val:42}.m();           // X::m()      , self == @
    (&X{val:42}).m();        // &X::m()     , self == @
    (&&X{val:42}).m();       // &&X::m()    , self == @
    (&&&X{val:42}).m();      // &&&X:m()    , self == @
    (&&&&X{val:42}).m();     // &&&X::m()   , self == *@
    (&&&&&X{val:42}).m();    // &&&X::m()   , self == **@

    (*X{val:42}).refm();     // i32::refm() , self == @
    X{val:42}.refm();        // X::refm()   , self == @
    (&X{val:42}).refm();     // X::refm()   , self == *@
    (&&X{val:42}).refm();    // &X::refm()  , self == *@
    (&&&X{val:42}).refm();   // &&X::refm() , self == *@
    (&&&&X{val:42}).refm();  // &&&X::refm(), self == *@
    (&&&&&X{val:42}).refm(); // &&&X::refm(), self == **@

    Y{val:42}.refm();        // i32::refm() , self == *@
    Z{val:Y{val:42}}.refm(); // i32::refm() , self == **@

    A.m();                   // A::m()      , self == @
    // without the Copy trait, (&A).m() would be a compilation error:
    // cannot move out of borrowed content
    (&A).m();                // A::m()      , self == *@
    (&&A).m();               // &&&A::m()   , self == &@
    (&&&A).m();              // &&&A::m()   , self == @
    A.refm();                // A::refm()   , self == @
    (&A).refm();             // A::refm()   , self == *@
    (&&A).refm();            // A::refm()   , self == **@
    (&&&A).refm();           // &&&A::refm(), self == @
}

Yani, bu, daha fazla veya daha az görünüyor:

  • Derleyici gerektiği kadar başvuru operatörler bir yöntemi çağırmak için ekleyecektir.
  • Yöntemleri &self (- by-call başvurusu) kullanarak ilan çözerken derleyici:
    • İlk self tek bir başvuru için seslendi
    • Sonra self tam tipi için seslendi
    • Sonra, başvuru operatörler birçok maç için gerekli olduğu kadar ekleme çalışır
  • Yöntemleri self kullanarak ilan (aramakopyaladeğeri) türü T hareket halinde oldukları bildirildi kullanarak &self (call-by-reference) türü &T olarak başvurmak için ne varsa sol tarafındaki nokta operatörü.
  • Yukarıdaki kuralları ilk yerleşik kaldırma ham ile çalıştı ve eğer uyuşursa yok, Deref özelliği ile aşırı kullanılır.

Ancak, gerçekten gerçeklik maç görünmüyor - (&A).m() çağırma açık &&&A, aynı çalıştım ama işlem yapmayacak.@87 **'deki yorum benim bu yanlış anlaşılma çözüldü.

Tam otomatik-kaldırma kuralları nelerdir? Kimse böyle bir tasarım kararı için herhangi bir resmi gerekçe verebilir misiniz?

CEVAP
16 ŞUBAT 2015, PAZARTESİ


Kod pseudo çok fazla doğru. Bu örneğin, bir yöntem foo: T ** * * * 12 * çağrı aldık varsayalım. UFCS yöntemi, *örneğin 14* A::bar(&***foo) ile çağrıldığını ne hakkında açık olmak için kullanacağım. Ben burada yazmak için bir yığın rastgele harfler, her biri sadece bazı keyfi tipi/özelliği dışında T her zaman bu tür orijinal değişken foo Bu yöntemi çağrılır.

Algoritma çekirdek:

  • each "dereference step" U Her (U = T olarak ayarlayın ve daha sonra 20*,...*)
    1. eğer bir yöntem, alıcı türü (yöntemi self türü) tam olarak U eşleştiği bar eğer orada , (a "by value method") kullanın
    2. aksi takdirde, ekleyin bir oto-ilan no (& &mut alıcı), ve, eğer bazı yöntemin alıcı maçlar &U kullanın (an "autorefd method")

Özellikle, her şeyi "" yöntemi, . alıcı türü olarak kabul etmektedir ^em>değilözelliği Self türü, yani impl ... for Foo { fn method(&self) {} } yöntemi eşleşen zaman &Foo düşünür fn method2(&mut self) eşleştirme &mut Foo düşünmek istiyorum.

Eğer iç adımları (yani, sıfır ya da bir özellik yöntemleri 1 her biri için geçerli olabilir. birden fazla özellik yöntemleri geçerli eğer orada bir hata vardır ya da 2., ama tek geçerli her olabilir: 1 dan biri alınacak ilk olacak), ve doğal yöntemler özelliği olanlar önceliklidir. Ayrıca eğer eşleşen hiçbir şey bulamadan döngünün sonuna ulaşırsak bir hata. Ayrıca sonsuz döngü yapmak Deref özyinelemeli uygulamaları için bir hatadır (vururlar "") özyineleme sınırı.

Bu kurallar görünmek için yapmak-ne-ben-yani en koşullara rağmen, sahip yeteneği yazmak için net UFCS form çok yararlı bazı kenar durumlarda, mantıklı hata iletileri için makro tarafından oluşturulan bir kod.

Sadece bir oto-başvuru nedeniyle eklenir

  • eğer bağlı olsaydı, her tür başvuruları alınan rasgele bir sayı olabilir beri kötü/yavaş
  • alarak bir referans &foo korur güçlü bir bağlantı için foo (adresi foo kendisi), ama daha fazla almaya başlar kaybetmek: &&foo Adres bazıları geçici değişken yığında saklar &foo.

Örnekler

Bir ara biz varsayalım eğer foo türü varsa, 38**,:

  • X başlıyoruz U = X, refm alıcı tipi &..., Adım 1 de uymuyor, alarak otomatik ilan no verir bize &X ve bu maç (Self = X), çağrı RefM::refm(&foo)
  • * *47, ilk adımda &self maçlar U = &X (Self = X) ile başlar ve arama RefM::refm(foo)
  • &&&&&X, bu uymuyor ya da adım (özellik değil uygulanan &&&&X &&&&&X), bu yüzden biz başvuru bir kez olsun U = &&&&X hangi maçlar 1 (Self = &&&X) ve arama RefM::refm(*foo)
  • Z, uymuyor ya adım çok başvuru yapıldı bir kez olsun Y, da uymuyor, o yüzden tekrar başvuru yapıldı, X, yok maçı 1-maçtan sonra autorefing, o yüzden Ara RefM::refm(&**foo).
  • &&A, 1. maç değil de 2 yapar. özelliği &A (1) veya &&A (2) için uygulanan olmadığından, maçlar &A, 1. başvuru yapıldı, Self = A ile

foo.m() ve A foo türü: 69 *değil* değil varsayalım

  • A U = A arama Self = A 74 *doğrudan self maçlar
  • * *76, 1. maç değil de 2 yapar. (ne &A ne &&A uygulamak özelliği), yani başvuru yapıldı A, maç, ancak M::m(*foo) gerektirir alarak A değer ve dolayısıyla hareket foo, dolayısıyla hata.
  • *, 1 *83. uymuyor, ama autorefing arama Self = &&&A M::m(&foo) çok maç yapan &&&A veriyor.

(Bu cevap* *91 is reasonably close to the (slightly outdated) README dayanmaktadır. Niko Matsakis, derleyici/dil bu bölümünün ana yazar, ayrıca bu cevabı göz önüne alın.)

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Bennythecoder

    Bennythecode

    25 Mart 2008
  • hotstrikegently

    hotstrikegen

    26 AĞUSTOS 2011
  • ThePointblank

    ThePointblan

    18 Aralık 2006