2016-07-26 16 views
5

Tôi có các bộ sưu tập được bán trên đĩa. Khi được yêu cầu, các bộ sưu tập này sẽ được truy xuất (không có vấn đề gì) và cần phải xây dựng một bộ sưu tập iterator để trả về các tham chiếu đến các giá trị đã truy xuất.Lặp lại bộ sưu tập. Thả nó ngay sau khi Iterator bị xóa

Sau khi số iterator bị xóa, tôi không cần bộ sưu tập nữa. Tôi cũng muốn nó bị bỏ.

Những gì tôi đã cố gắng cho đến nay:

  1. Các Iterator sở hữu bộ sưu tập. Điều này có ý nghĩa nhất đối với tôi, nhưng điều đó là không thể; Tôi không hoàn toàn chắc chắn tại sao. Một số người nói rằng chữ ký phương thức của các đặc điểm Iterator cho next là vấn đề. (example)

  2. Đếm tham chiếu: Retriever trả về Rc<Vec<usize>>. Tôi chạy vào các vấn đề tương tự như trong iterator sở hữu. (example)

  3. Cho phép trình thu thập sở hữu bộ sưu tập và đưa ra một tham chiếu đến bộ sưu tập đó. Tôi đã cố gắng để thực hiện các retriever với mutability nội thất (RefCell<HashMap>), nhưng tôi không thể trở lại tài liệu tham khảo vào HashMap với tuổi thọ đủ dài.

Tôi thấy hai khả năng cơ bản với điều này.

  1. Quyền truy xuất chuyển quyền sở hữu. Sau đó, Iterator sẽ cần phải sở hữu dữ liệu. Nội dung nào đó trong dòng:

    use std::slice::Iter; 
    
    fn retrieve(id: usize) -> Vec<usize> { 
        //Create Data out of the blue (or disk, or memory, or network. I dont care) 
        //Move the data out. Transfer ownership 
        let data = vec![0, 1, 2, 3]; 
        data 
    } 
    
    fn consume_iterator<'a, TIterator: Iterator<Item=&'a usize>>(iterator: TIterator) { 
        for i in iterator { 
         println!("{}", i); 
        } 
    } 
    
    fn handler<'a>(id: usize) -> Iter<'a, usize> { 
        //handle_request now owns the vector. 
        //I now want to build an owning iterator.. 
        //This does of course not compile as vector will be dropped at the end of this method 
        retrieve(id).iter() 
    } 
    
    fn main() { 
        consume_iterator(handler(0)) 
    } 
    
  2. Trình truy xuất sở hữu bộ sưu tập. Nhưng sau đó có hai vấn đề mới phát sinh:

    1. Làm cách nào để thả dữ liệu khi trình vòng lặp nằm ngoài phạm vi?
    2. Làm cách nào để nói với người mượn tiền rằng tôi sẽ sở hữu bộ sưu tập đủ lâu?

    use std::cell::{Ref, RefCell}; 
    
    struct Retriever { 
        //Own the data. But I want it to be dropped as soon as the references to it go out of scope. 
        data: RefCell<Vec<usize>> 
    } 
    
    impl Retriever{ 
    
        fn retrieve<'a>(&'a self, id: usize) -> Ref<'a, Vec<usize>> { 
         //Create Data out of the blue (or disk, or memory, or network. I dont care) 
         //Now data can be stored internally and a referece to it can be supplied. 
         let mut data = self.data.borrow_mut(); 
         *data = vec![0, 1, 2, 3]; 
         self.data.borrow() 
        } 
    
    } 
    
    fn consume_iterator<'a, TIterator: Iterator<Item=&'a usize>>(iterator: TIterator) { 
        for i in iterator { 
         println!("{}", i); 
        } 
    } 
    
    
    fn handler<'a>(ret: &'a Retriever, id: usize) -> IterWrapper<'a> { 
        //andle_request now has a reference to the collection 
        //So just call iter()? Nope. Lifetime issues. 
        ret.retrieve(id).iter()   
    } 
    
    fn main() { 
        let retriever = Retriever{data: RefCell::new(Vec::new())}; 
        consume_iterator(handler(&retriever, 0)) 
    } 
    

tôi cảm thấy một chút mất ở đây và đang nhìn cái gì đó rõ ràng.

+1

Tôi nghĩ bạn cần ['std :: vec :: IntoIter'] (https://doc.rust-lang.org/stable/std/vec/struct.IntoIter.html): https: // play. rust-lang.org/?gist=0e6c171c08fc7a314c44ac98f3dd398e&version=stable&backtrace=0 Nhưng sau đó bạn cũng có thể sử dụng trực tiếp 'IntoIter'. – Dogbert

+0

Trong khi đó sẽ biên dịch, 'IntoIter' di chuyển các giá trị. Đầu nhận của 'Iterator' dự kiến ​​tham chiếu đến các giá trị. Tôi sẽ cập nhật câu hỏi của tôi cho phù hợp – JDemler

+3

Tôi sợ bạn đã bằng cách nào đó chạy vào [Vấn đề XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) ... Tại sao Bạn có cần tham chiếu đến các giá trị, nếu bạn không cần các giá trị sau đó? Toàn bộ điểm vay là vì vậy bạn giữ quyền sở hữu, nhưng dường như bạn không muốn giữ quyền sở hữu. –

Trả lời

1

bây giờ tôi là cuối cùng có thể thực hiện một giải pháp tương đối statisfying:

Ẩn các mutability của vòng lặp bên Cell s:

pub trait OwningIterator<'a> { 
    type Item; 
    fn next(&'a self) -> Option<Self::Item>; 
} 

Một struct bây giờ cần một vị trí Cell d để cho phép lặp lại mà không đột biến. Như một ví dụ ở đây là việc thực hiện một cấu trúc mà cả hai đang sở hữu và có thể lặp lại trên một Arc<Vec<T>>:

pub struct ArcIter<T> { 
    data: Arc<Vec<T>>, 
    pos: Cell<usize>, 
} 

impl<'a, T: 'a> OwningIterator<'a> for ArcIter<T> { 
    type Item = &'a T; 

    fn next(&'a self) -> Option<Self::Item> { 
     if self.pos.get() < self.data.len() { 
      self.pos.set(self.pos.get() + 1); 
      return Some(&self.data[self.pos.get() - 1]); 
     } 
     None 
    } 
} 

Như tôi đã có thể ẩn các loại vòng lặp đằng sau giao diện và cho phép người dùng chỉ xử lý lặp "thật" Tôi cảm thấy đây là độ lệch chấp nhận được từ tiêu chuẩn.

Nhờ tất cả những người đóng góp với ý tưởng cuối cùng đã giúp tôi tìm ra giải pháp đó.

4

Iterator sở hữu bộ sưu tập. [Hoặc sở hữu chung thông qua tham khảo đếm]

ContainerIterator { 
    data: data, 
    iter: data.iter(), 
} 

Không, bạn cannot have a value and a reference to that value in the same struct.

Cho phép trình thu thập sở hữu bộ sưu tập và đưa ra một tham chiếu đến bộ sưu tập đó.

Không, bạn cannot return references to items owned by the iterator.

Như bình luận đã nói, sử dụng IntoIter chuyển quyền sở hữu của các mục để các iterator và sau đó tay chúng ra như các giá trị lặp:

use std::vec::IntoIter; 

struct ContainerIterator { 
    iter: IntoIter<usize>, 
} 

impl Iterator for ContainerIterator { 
    type Item = usize; 

    fn next(&mut self) -> Option<Self::Item> { 
     self.iter.next() 
    } 
} 

fn main() { 
    let data = vec![0, 1, 2, 3]; 
    let cont = ContainerIterator { iter: data.into_iter() }; 

    for x in cont { 
     println!("Hi {}", x) 
    } 
} 

Nếu bạn phải trở lại tài liệu tham khảo ... sau đó bạn cần để giữ những thứ sở hữu chúng trong suốt thời gian mà tất cả các tài liệu tham khảo có thể xung quanh.

Làm cách nào để thả dữ liệu khi trình vòng lặp nằm ngoài phạm vi?

Bằng không sử dụng giá trị nữa:

fn main() { 
    { 
     let loaded_from_disk = vec![0, 1, 2, 3]; 
     for i in &loaded_from_disk { 
      println!("{}", i) 
     } 
     // loaded_from_disk goes out of scope and is dropped. Nothing to *do*, per se. 
    } 
} 

Làm thế nào để nói với mượn trình kiểm tra mà tôi sẽ sở hữu bộ sưu tập đủ lâu?

Bằng cách sở hữu bộ sưu tập đủ dài. Không có cái bắt tay bí mật nào mà Rust Illuminati sử dụng cùng với người mượn mượn. Mã chỉ cần được cấu trúc sao cho điều vay mượn không trở thành không hợp lệ trong khi khoản vay còn tồn tại. Bạn không thể di chuyển nó (thay đổi địa chỉ bộ nhớ) hoặc thả nó (thay đổi địa chỉ bộ nhớ).

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