2016-07-06 7 views
5

हमारे पास structs की एक डबल समाप्ति सूची है, उदा। LinkedListआगे और पीछे

मुझे तत्वों के माध्यम से आगे और पिछड़े पुनरावृत्त करने की आवश्यकता है (जैसे, 4 गुना आगे 2 बार पीछे 5 बार आगे)।

C++ में यह होगा:

iter++; iter++; ... iter--; ... 

जंग में, मैं केवल देखने .next() और .rev() जो असुविधाजनक है (के बाद से कुछ पुनरावृत्तियों के बाद मैं पहले से ही पता नहीं है किस दिशा में मैं यात्रा निरस्त कर दिया है)।

+4

वास्तव में '.rev()' संभव है कि आप उम्मीद नहीं है। यह इटेटरेटर को उलट देता है, इसलिए अब आप पीछे से तत्व ले रहे हैं। –

+2

नोट: सी ++ में आपको पूर्व-वृद्धि/पूर्व-कमी का उपयोग करना चाहिए, यह इटरेटर के आधार पर थोड़ा अधिक से अधिक कुशलता से भिन्न होता है। –

उत्तर

4

Iterator सी ++ के ForwardIterator के समान है। आप जो चाहते हैं वह BidirectionalIterator है, लेकिन जंग प्रणाली के प्रकार की सीमा के कारण इसी तरह की विशेषता प्रदान नहीं करती है।

Matthieu M टिप्पणियों में कहा गया है, जिस तरह से एक इटरेटर परिभाषित किया गया है, उपजित तत्व को संदर्भित करने के लिए संदर्भ देता है। और यह एक समस्या है यदि पुनरावर्तक उत्परिवर्ती संदर्भ उत्पन्न करता है, क्योंकि आगे और पीछे जाने से गुणक एक ही तत्व के उत्परिवर्तनीय संदर्भों की अनुमति देंगे। इस समस्या को हल करने का एक तरीका &mut self के साथ उपजित तत्व के जीवनकाल को बांधना होगा, इसलिए next (या prev) पर कॉल self उधार लेगा, लेकिन इसे सामान्य तरीके से करने का कोई तरीका नहीं है (RFC है ऐसी क्षमता जोड़ें)।

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

हम देख सकते हैं कि Self::Item के जीवनकाल 'a से स्वतंत्र है:

Iterator विशेषता परिभाषा देख रहे हैं। समस्या को हल करने के लिए क्या आवश्यक है:

pub trait Iterator { 
    type Item<'a>; // hypothetical syntax 
    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; 
    // ... 
} 

लेकिन यह अभी तक समर्थित नहीं है।


जिसके अनुसार, एक विकल्प के लिए एक बाहरी टोकरा, जो किसी विशेष इटरेटर का उपयोग (जो है, एक विशेषता को लागू नहीं करते) का प्रयोग है।

use linked_list::LinkedList; 
use std::iter::FromIterator; 

fn main() { 
    // LinkedList::cursor takes &mut self, so lst must be mutable 
    let mut lst = LinkedList::from_iter(0..10); 
    let mut c = lst.cursor(); 

    c.next(); 
    c.next(); 
    c.next(); 
    c.prev(); 

    assert_eq!(1, *c.prev().unwrap()); 
} 

Cursor झुकेंगे तत्व के लिए संदर्भ रखा जाना अनुमति नहीं देता: linked_list टोकरा Cursor साथ एक लिंक्ड सूची कार्यान्वयन, कि आगे की अनुमति देता है और पीछे की ओर यात्रा प्रदान करता है। डॉक्स का कहना है:

A Cursor is like an iterator, except that it can freely seek back-and-forth, and can safely mutate the list during iteration. This is because the lifetime of its yielded references is tied to its own lifetime, instead of just the underlying list. This means cursors cannot yield multiple elements at once.

निम्न उदाहरण:

error: cannot borrow `c` as mutable more than once at a time [E0499] 
    let b = c.next(); 

यह इसलिए होता है क्योंकि next (और prev) self से उधार लेता है, वह यह है कि:

let a = c.next(); 
let b = c.next(); 

इस त्रुटि उत्पन्न करता है

fn next<'a>(&'a mut self) -> Option<&'a mut T> 
+3

कारण बस उत्परिवर्तन बनाम अलियासिंग है। 'इटरेटर' डिज़ाइन किया गया है ताकि आप जो तत्व पैदा हुए तत्वों के संदर्भ बनाए रख सकें, ताकि यदि आप आगे और आगे जा सकें तो आप उसी तत्व (उर्फ: एलियासिंग) के कई संदर्भ प्राप्त कर पाएंगे। अब, कल्पना करें कि प्रश्न में संदर्भ म्यूटेबल हैं: अब आपके पास एक ही तत्व, BOOM के एकाधिक म्यूटेबल संदर्भ हैं। इसलिए, चूंकि परिवर्तनीय संदर्भ प्रदान करना वांछनीय है, इसलिए 'इटरेटर' विशेषता ने अलियासिंग को छोड़ दिया है। –

2

ऐसा करने के लिए आपको अपना खुद का इटरेटर लागू करना होगा।यहाँ Vec रों के लिए एक का एक नमूना कार्यान्वयन है:

pub trait ForwardBackwardIterator : Iterator { 
    fn prev(&mut self) -> Option<Self::Item>; 
} 

pub struct VectorForwardBackwardIterator<'a, Item> where Item : 'a { 
    index: Option<usize>, 
    vector: &'a Vec<Item>, 
} 

impl<'a, Item> VectorForwardBackwardIterator<'a, Item> { 
    fn new(vector: &'a Vec<Item>) -> VectorForwardBackwardIterator<'a, Item> { 
     VectorForwardBackwardIterator { index: None, vector: vector } 
    } 
} 

impl<'a, Item> Iterator for VectorForwardBackwardIterator<'a, Item> { 
    type Item = &'a Item; 

    fn next(&mut self) -> Option<&'a Item> { 
     let index = 
      match self.index { 
       Some(i) => i + 1, 
       None => 0 
      }; 

     self.index = Some(index); 
     self.vector.get(index) 
    } 
} 

impl<'a, Item> ForwardBackwardIterator for VectorForwardBackwardIterator<'a, Item> { 
    fn prev(&mut self) -> Option<&'a Item> { 
     let index = 
      match self.index { 
       Some(0) | None => return None, 
       Some(i) => i - 1 
      }; 

     self.index = Some(index); 
     self.vector.get(index) 
    } 
} 

fn main() { 
    let v = vec![0, 1, 2, 3, 4, 5]; 
    let mut iterator = VectorForwardBackwardIterator::new(&v); 

    println!("{:?}", iterator.next()); 
    println!("{:?}", iterator.next()); 
    println!("{:?}", iterator.next()); 
    println!("{:?}", iterator.prev()); 
    println!("{:?}", iterator.prev()); 
} 

यह बाहर प्रिंट

Some(0) 
Some(1) 
Some(2) 
Some(1) 
Some(0) 
संबंधित मुद्दे