2015-02-28 15 views
5

Tôi muốn sử dụng Peekable làm cơ sở cho hoạt động cautious_take_while hoạt động như take_while từ IteratorExt nhưng không tiêu thụ mục không thành công đầu tiên. (Có một câu hỏi phụ là liệu đây có phải là một ý hay hay không và liệu có cách nào tốt hơn để hoàn thành mục tiêu này trong Rust), tôi rất vui vì những gợi ý theo hướng đó, nhưng chủ yếu là tôi đang cố hiểu mã của tôi ở đâu phá vỡ).Thực hiện lệnh "thận trọng" khi sử dụng Peekable

API Tôi đang cố gắng để cho phép cơ bản là:

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

Tôi đã lấy một vết nứt ở creating a MCVE here, nhưng tôi nhận được:

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

Theo như tôi có thể nói , Tôi đang theo cùng một mẫu như của riêng Rust của TakeWhile về chữ ký chức năng của tôi, nhưng tôi thấy hành vi khác nhau khác nhau từ kiểm tra vay. Ai đó có thể chỉ ra những gì tôi đang làm sai?

Trả lời

5

Điều buồn cười với by_ref() là nó trả về một tài liệu tham khảo có thể thay đổi với bản thân:

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

Nó hoạt động vì Iterator đặc điểm được thực hiện cho con trỏ có thể thay đổi để iterator loại. Thông minh!

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

Tiêu chuẩn take_while chức năng làm việc vì nó sử dụng các đặc điểm Iterator, cũng được giải quyết để &mut Peekable<T>.

Nhưng mã của bạn không hoạt động vì Peekable là cấu trúc, không phải là đặc điểm, vì vậy, CautiousTakeWhileable phải chỉ định loại và bạn đang cố gắng sở hữu nó, nhưng bạn không thể, vì bạn có một con trỏ có thể thay đổi.

Giải pháp, không dùng Peekable<T> nhưng &mut Peekable<T>. Bạn sẽ cần phải xác định thời gian tồn tại quá:

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

Một tác dụng phụ tò mò của giải pháp này là bây giờ by_ref là không cần thiết, bởi vì cautious_take_while() mất một tài liệu tham khảo có thể thay đổi, vì vậy nó không ăn cắp quyền sở hữu. Cuộc gọi by_ref() là cần thiết cho take_while() vì có thể mất Peekable<T> hoặc &mut Peekable<T> và cuộc gọi mặc định là số đầu tiên. Với cuộc gọi by_ref(), cuộc gọi sẽ chuyển sang cuộc gọi thứ hai.

Và bây giờ mà cuối cùng tôi hiểu nó, tôi nghĩ rằng nó có thể là một ý tưởng tốt để thay đổi định nghĩa của struct CautiousTakeWhile để bao gồm các bit peekable vào struct chính nó. Khó khăn là cuộc đời phải được xác định bằng tay, nếu tôi đúng.Một cái gì đó như:

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

và phần còn lại ít nhiều đơn giản.

+0

Cảm ơn @rodrigo! Tôi đã kết hợp đề xuất đầu tiên của bạn để tạo một ví dụ làm việc tại http://is.gd/NalTYL. Nhưng khi tôi cố gắng đưa cách gõ vào cấu trúc, như trong http://is.gd/6c64vf, tôi nhận được 'lỗi: đặc điểm * core :: clone :: Clone * không được triển khai cho loại * & mut core: : iter :: Peekable * ', điều mà tôi không thể vượt qua bằng cách thêm' + Clone' vào giới hạn đặc điểm trong dòng 43. – Bosh

+0

@Bosh. Không chắc chắn, nhưng tôi nghĩ rằng một con trỏ có thể thay đổi không thể được nhân bản. Biến thể của bạn chấp nhận 'Clone' có lẽ vì' Peekable' ngụ ý 'Clone' một cách rõ ràng. Có lẽ bạn có thể làm tương tự, nhưng mã sẽ cần một số tái cấu trúc ... – rodrigo

+1

Tuyệt vời. Tôi đã ngừng phát sinh từ 'Clone' và dọn dẹp các mốc thời gian: http://is.gd/ljjJAE. Một lần nữa xin cảm ơn sự giúp đỡ của bạn + giải thích! – Bosh

1

Đây là một điều khó khăn! Tôi sẽ dẫn đầu với mã số của mã, sau đó cố gắng giải thích nó (nếu tôi hiểu nó ...). Nó cũng là phiên bản xấu xí, không được giải phóng, vì tôi muốn giảm sự phức tạp ngẫu nhiên.

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

Thực ra, Rodrigo seems to have a good explanation, vì vậy tôi sẽ trì hoãn điều đó, trừ khi bạn muốn tôi giải thích điều gì đó cụ thể.

Các vấn đề liên quan