2015-02-28 15 views
5

kullanarak take_while "ihtiyatlı" Ben IteratorExt den take_while gibi ama ilk başarısız öğeyi tüketmeden davranan bir yeni cautious_take_while operasyon için temel olarak Peekable kullanmak istiyorum uygulanması. (Bunun iyi bir fikir olup olmadığı ve bu amacı Rust'ta gerçekleştirmenin daha iyi bir yolu olup olmadığı sorusu var - bu yönde ipuçları için mutlu olurum, ancak çoğunlukla kodumun nerede olduğunu anlamaya çalışıyorum. kırma).Peekable

let mut chars = "abcdefg.".chars().peekable(); 

let abc : String = chars.by_ref().cautious_take_while(|&x| x != 'd'); 
let defg : String = chars.by_ref().cautious_take_while(|&x| x != '.'); 

// yielding (abc = "abc", defg = "defg") 

Ben creating a MCVE here bir çatlak geçtiniz, ama ben alıyorum:

Ben etkinleştirmek için çalışıyorum API temelde Bildiğim kadarıyla söyleyebilirim

:10:5: 10:19 error: cannot move out of borrowed content :10 chars.by_ref().cautious_take_while(|&x| x != '.');

Ben, fonksiyon imzam açısından, Rust'un kendi TakeWhile ile aynı modeli takip ediyorum, fakat borç kontrolöründen farklı farklı davranışlar görüyorum. Birisi yanlış yaptığım şeye işaret edebilir mi?

cevap

5

by_ref() ile komik bir şey kendisi için bir değişken başvuru verir olmasıdır:

Iterator özellik türünü Iterasyon için değişken pointer için uygulanan çünkü çalışır
pub trait IteratorExt: Iterator + Sized { 
    fn by_ref(&mut self) -> &mut Self { self } 
} 

. Akıllı! o özelliği Iterator, otomatik olarak &mut Peekable<T> çözümlenir kullandığı için

impl<'a, I> Iterator for &'a mut I where I: Iterator, I: ?Sized { ... } 

standart take_while fonksiyon

çalışır.

Ancak kodunuz çalışmıyor, çünkü Peekable bir özellik değil, bir özelliktir, bu nedenle CautiousTakeWhileable türünü belirtmeniz gerekir ve bunun türünü almaya çalışmanız gerekir, ancak bunu yapamazsınız, çünkü değişken bir işaretçiniz vardır.

Çözüm, Peekable<T> ama &mut Peekable<T> almayın. Sen de ömrünü belirtmek gerekir:

impl <'a, T: Iterator, P> Iterator for CautiousTakeWhile<&'a mut Peekable<T>, P> 
where P: FnMut(&T::Item) -> bool { 
    //... 
} 

impl <'a, T: Iterator> CautiousTakeWhileable for &'a mut Peekable<T> { 
    fn cautious_take_while<P>(self, f: P) -> CautiousTakeWhile<&'a mut Peekable<T>, P> 
    where P: FnMut(&T::Item) -> bool { 
     CautiousTakeWhile{inner: self, condition: f,} 
    } 
} 

bu çözümün Meraklı yan etkisi cautious_take_while() bir değişken referans alır, bu yüzden sahipliğini çalmak değil çünkü, şimdi by_ref gerekli değildir olmasıdır. by_ref() çağrısı take_while() için gereklidir, çünkü Peekable<T> veya &mut Peekable<T>'u alabilir ve ilk olarak varsayılan değerdir. by_ref() çağrısı ile ikinciye çözecektir.

Ve şimdi sonunda anladığım kadarıyla, görülebilir bitin yapının kendisine eklenmesini sağlamak için struct CautiousTakeWhile tanımını değiştirmek iyi bir fikir olabilir. Zorluk, eğer haklıysam, yaşamın manüel olarak belirtilmesi gerekiyor.gibi bir şey:

struct CautiousTakeWhile<'a, T: Iterator + 'a, P> 
    where T::Item : 'a { 
    inner: &'a mut Peekable<T>, 
    condition: P, 
} 
trait CautiousTakeWhileable<'a, T>: Iterator { 
    fn cautious_take_while<P>(self, P) -> CautiousTakeWhile<'a, T, P> where 
     P: FnMut(&Self::Item) -> bool; 
} 

ve dinlenme az ya da çok basittir.

+0

Teşekkürler @rodrigo! Http://is.gd/NalTYL adresinde çalışan bir örnek oluşturmak için ilk önerinizi ekledim. Ancak, yazımı http://is.gd/6c64vf dosyasında olduğu gibi yazmayı denediğimde, hata alıyorum: trait * core :: clone :: Clone *, * ve mut core türünde uygulanmadı: : iter :: Peekable * ', satır 43'teki satır sınırlarına' + Clone 'ekleyerek üstesinden gelemiyorum. – Bosh

+0

@Bosh. Emin değilim, ama değişebilen bir işaretçinin klonlanamayacağını düşünüyorum. Değişkeniniz muhtemelen "Clone" ı kabul eder, çünkü 'Peekable' implantasyonu' Clone 'açık bir şekilde. Belki de aynısını yapabilirsin, ama kodun bir miktar refactoringe ihtiyacı var ... – rodrigo

+1

Harika. "Clone" dan türetmeyi durdurdum ve zaman çizelgelerini temizledim: http://is.gd/ljjJAE. Yardımlarınız ve açıklamalarınız için tekrar teşekkürler! – Bosh

1

Bu zor bir şeydi! Kodun etiyle başa çıkacağım, sonra açıklamaya çalışacağım (anladığım kadarıyla ...). Ayrıca, rastlantısal karmaşıklığı azaltmak istediğim için çirkin, tekdüze versiyon. Eğer belirli bir şey açıklamak beni istiyorum sürece

use std::iter::Peekable; 

fn main() { 
    let mut chars = "abcdefg.".chars().peekable(); 

    let abc: String = CautiousTakeWhile{inner: chars.by_ref(), condition: |&x| x != 'd'}.collect(); 
    let defg: String = CautiousTakeWhile{inner: chars.by_ref(), condition: |&x| x != '.'}.collect(); 
    println!("{}, {}", abc, defg); 
} 

struct CautiousTakeWhile<'a, I, P> //' 
    where I::Item: 'a, //' 
      I: Iterator + 'a, //' 
      P: FnMut(&I::Item) -> bool, 
{ 
    inner: &'a mut Peekable<I>, //' 
    condition: P, 
} 

impl<'a, I, P> Iterator for CautiousTakeWhile<'a, I, P> 
    where I::Item: 'a, //' 
      I: Iterator + 'a, //' 
      P: FnMut(&I::Item) -> bool 
{ 
    type Item = I::Item; 

    fn next(&mut self) -> Option<I::Item> { 
     let return_next = 
      match self.inner.peek() { 
       Some(ref v) => (self.condition)(v), 
       _ => false, 
      }; 
     if return_next { self.inner.next() } else { None } 
    } 
} 

Aslında Rodrigo seems to have a good explanation, bu yüzden, bu ertelemek gerekir.