2015-02-28 4 views
5

Я хотел бы использовать Peekable в качестве основы для новой cautious_take_while операции, которая действует как take_while от IteratorExt, но не потребляя первую неудачную деталь. (Есть вопрос о том, является ли это хорошей идеей, и есть ли лучшие способы достижения этой цели в Rust - я был бы рад за намеки в этом направлении, но в основном я пытаюсь понять, где мой код ломки)., реализующий «осторожный» take_while использования Peekable

API-интерфейс, я пытаюсь включить в основном:

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

Я взял трещину в creating a MCVE here, но я получаю:

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

Насколько я могу сказать , Я придерживаюсь той же модели, что и у Rust's TakeWhile с точки зрения моих подписей функций, но я вижу различное поведение от заимствования. Может кто-то указать, что я делаю неправильно?

ответ

5

Самая смешным с by_ref(), что она возвращает изменяемую ссылку на себя:

pub trait IteratorExt: Iterator + Sized { 
    fn by_ref(&mut self) -> &mut Self { self } 
} 

Это работает, потому что Iterator черта реализуется для изменяемого указателя на итератор типа. Умная!

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

Стандартная take_while функция работает, потому что она использует признак Iterator, который автоматически разрешен к &mut Peekable<T>.

Но ваш код не работает, потому что Peekable является структурой, а не чертой, поэтому ваш CautiousTakeWhileable должен указать тип, и вы пытаетесь завладеть им, но вы не можете, поскольку у вас есть изменяемый указатель.

Решение, не принимайте Peekable<T>, но &mut Peekable<T>. Вам нужно будет указать срок службы тоже:

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

любопытный побочный эффект этого решения заключается в том, что в настоящее время by_ref не требуется, потому что cautious_take_while() принимает изменяемую ссылку, так что не ворует собственность. Вызов by_ref() необходим для take_while(), потому что он может принимать либо Peekable<T>, либо &mut Peekable<T>, и по умолчанию он соответствует первому. С вызовом by_ref() он разрешит второй.

И теперь, когда я, наконец, понял это, я думаю, что было бы неплохо изменить определение struct CautiousTakeWhile, чтобы включить в его структуру фрагмент peekable. Трудность в том, что время жизни должно быть указано вручную, если я прав.Что-то вроде:

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

, а остальное более простое.

+0

Спасибо @rodrigo! Я включил ваше первое предложение для создания рабочего примера на http://is.gd/NalTYL. Но когда я пытаюсь ввести текст в структуру, как в http://is.gd/6c64vf, я получаю 'error: черта * core :: clone :: Clone * не реализована для типа * & mut core: : iter :: Peekable * ', который я, похоже, не могу преодолеть, добавив' + Clone' к границам признаков в строке 43. – Bosh

+0

@Bosh. Не уверен, но я думаю, что изменяемый указатель не может быть клонирован. Ваш вариант допускает «Clone», вероятно, потому, что «Peekable» использует «Clone» явно. Возможно, вы можете сделать то же самое, но для этого кода потребуется некоторое рефакторинг ... – rodrigo

+1

Отлично. Я остановился на «Clone» и очистил временные рамки: http://is.gd/ljjJAE. Еще раз спасибо за помощь + объяснения! – Bosh

1

Это было сложно! Я буду вести мясо с кодом, а затем попытаюсь объяснить его (если я это понимаю). Это также уродливая, безоговорочная версия, поскольку я хотел уменьшить случайную сложность.

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

На самом деле, Rodrigo seems to have a good explanation, так что я буду откладывать на это, если вы не хотите, чтобы я объяснить что-то конкретное.

 Смежные вопросы

  • Нет связанных вопросов^_^