2014-12-03 21 views
8

Wzorzec zachowania cechy obiektu Foo i (potencjalnie niebezpiecznej) cechy FooExt implementowanej dla wszystkich instancji Foo wydaje się teraz standardem.Praca nad ograniczeniami cech rozszerzenia

https://github.com/rust-lang/rfcs/pull/445

To jest dla mnie problemem w przypadku Iterator<A>, jak mam biblioteki, który zastępuje domyślną metodę IteratorExt#last() starego iteratora (cecha podstawowa biblioteka posiada sprawną realizację last()). To jest teraz niemożliwe, ponieważ dla każdego A zawsze będzie występować sprzeczna implementacja cechy IteratorExt, która już zapewnia libcore dla wszystkich .

iterator.rs:301:1: 306:2 error: conflicting implementations for trait `core::iter::IteratorExt` [E0119]

iterator.rs:301 impl<'a, K: Key> iter::IteratorExt<Vec<u8>> for ValueIterator<'a,K,Vec<u8>> { 
iterator.rs:302 fn last(&mut self) -> Option<Vec<u8>> { 
iterator.rs:303  self.seek_last(); 
iterator.rs:304  Some(self.value()) 
iterator.rs:305 } 
iterator.rs:306 } 
... 

Teraz, o ile widzę, mam dwie opcje:

  • mają własne cechy i moje własne last() realizację. Oznaczałoby to konflikt, jeśli zostanie zaimportowany, o ile nie zostanie starannie użyty. Zagrożenie to jest również przypadkowo używane w nieefektywnej wersji last(), jeśli używana jest wersja z IteratorExt. Pozbawiłbym dogodnego dostępu do IteratorExt.
  • Mam własną cechę i nazwę tej metody w inny sposób (seek_last()). Wada: proszę użytkownika, aby nauczył się słownictwa i zawsze faworyzował moją metodę nad tą dostarczoną przez IteratorExt. Ten sam problem: chciałbym uniknąć przypadkowego użycia last().

Czy istnieje inne, lepsze rozwiązanie, którego mi brakuje?

Odpowiedz

2

Od rustc 0.13.0-nightly (8bca470c5 2014-12-08 00:12:30 +0000) definiowanie last() jako nieodłączne metody na typ powinny działać.

#[deriving(Copy)] 
struct Foo<T> {t: T} 

impl<T> Iterator<T> for Foo<T> { 
    fn next(&mut self) -> Option<T> { None } 
} 

// this does not work 
// error: conflicting implementations for trait `core::iter::IteratorExt` [E0119] 
// impl<T> IteratorExt<T> for Foo<T> { 
// fn last(mut self) -> Option<T> { None } 
//} 

// but this currently does 
impl<T> Foo<T> { 
    fn last(mut self) -> Option<T> { Some(self.t) } 
} 


fn main() { 
    let mut t = Foo{ t: 3u }; 
    println!("{}", t.next()) 
    println!("{}", t.last()) // last has been "shadowed" by our impl 
    println!("{}", t.nth(3)) // other IteratorExt methods are still available 
} 

Ponieważ nie powinniśmy używać cechy rozciągnięcie granic generyczne (ale tylko w celu zapewnienia dodatkowych metod), to teoretycznie powinien pracować dla scenariusza, jak można mieć swój własny rodzaj i jego impl w taki sam skrzynia.

Użytkownicy typu użyje wrodzoną last sposób zamiast jednego na IteratorExt ale nadal będą mogli korzystać z innych metod na IteratorExt.

+0

Nie mogę uzyskać tego działającego z 'rustc 0.13.0-nightly (193390d0e 2014-12-11 22:56:54 +0000)'. Nie zastępuje metody, ostrzega o 'dead_code'. Podoba mi się to jednak jako rozwiązanie. – Skade

+0

Zarysuj to, nie upubliczniłem tej metody, aby użyć jej w innej skrzyni. Działa z 'pub fn last (...)'. – Skade

+0

Czy to na ogół działa w ogólnym kodzie, który pochłania taki typ (z połączeniem Iterator) i prawdopodobnie mieszka w innej skrzyni? – sellibitze

0

last powinny zostać przeniesione do Iterator, zamiast IteratorExt.

IteratorExt jest potrzebne do korzystania Box<Iterator> obiektów, aby umożliwić wywołanie metody rodzajowe na nich (np map), ponieważ nie można umieścić metody rodzajowe w vtable. Jednak last nie jest generyczny, więc można go umieścić w Iterator.

+0

Może to być rozwiązanie tego konkretnego problemu, ale pytanie dotyczy ogólnego rozwiązania dla cech rozszerzenia. – Shepmaster