2015-02-28 7 views
5

का उपयोग कर take_while मैं एक नया cautious_take_while आपरेशन कि take_whileIteratorExt से की तरह, लेकिन पहले विफल रही है आइटम लेने के बिना काम करता है के लिए आधार के रूप में Peekable उपयोग करना चाहते हैं। (यह एक अच्छा विचार है कि यह एक अच्छा विचार है, और क्या जंग में इस लक्ष्य को पूरा करने के बेहतर तरीके हैं - मैं उस दिशा में संकेतों के लिए खुश रहूंगा, लेकिन ज्यादातर मैं समझने की कोशिश कर रहा हूं कि मेरा कोड कहां है तोड़ना)।को लागू करने के लिए एक "सतर्क" 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") 

मैं creating a MCVE here देने का प्रयास कर लिया है, लेकिन मैं हो रही है:

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

जहां तक ​​मेरा बता सकते हैं , मैं अपने फ़ंक्शन हस्ताक्षर के संदर्भ में जंग के अपने TakeWhile के समान पैटर्न का पालन कर रहा हूं, लेकिन मैं उधार चेकर से अलग-अलग व्यवहार देख रहा हूं। क्या कोई यह बता सकता है कि मैं क्या गलत कर रहा हूं?

उत्तर

5

by_ref() साथ अजीब बात यह है कि यह अपने आप के लिए एक परिवर्तनशील संदर्भ देता है:

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

यह काम करता है क्योंकि Iterator विशेषता प्रकार iterator को परिवर्तनशील सूचक के लिए लागू किया गया है। होशियार!

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

मानक take_while समारोह काम करता है क्योंकि यह का उपयोग करता है विशेषता Iterator, कि स्वचालित रूप से &mut Peekable<T> का संकल्प लिया है।

लेकिन अपने कोड काम नहीं करता क्योंकि Peekable एक struct, नहीं एक विशेषता है, इसलिए क्योंकि आप एक परिवर्तनशील सूचक है अपने 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 की परिभाषा को बदलने के लिए एक अच्छा विचार हो सकता है ताकि संरचना में खुद को देखने योग्य बिट शामिल किया जा सके। कठिनाई यह है कि अगर मैं सही हूं, तो जीवन भर को मैन्युअल रूप से निर्दिष्ट करना होगा।कुछ ऐसा:

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 में, मुझे 'त्रुटि मिलती है: विशेषता * कोर :: क्लोन :: क्लोन * प्रकार * और म्यूट कोर के लिए लागू नहीं किया गया है: : iter :: Peekable * ', जिसे मैं लाइन 43 में विशेषता सीमाओं में' + क्लोन' जोड़कर दूर नहीं लग सकता। – Bosh

+0

@ बॉश। यकीन नहीं है, लेकिन मुझे लगता है कि एक परिवर्तनीय सूचक को क्लोन नहीं किया जा सकता है। आपका संस्करण 'क्लोन' को स्वीकार करता है क्योंकि संभवतः 'पिकेबल' स्पष्ट रूप से 'क्लोन' को इम्प्लांट करता है। शायद आप वही कर सकते हैं, लेकिन कोड को कुछ रिफैक्टरिंग की आवश्यकता होगी ... – rodrigo

+1

ग्रेट। मैंने 'क्लोन 'से निकलने से रोक दिया और समय सीमा साफ कर दी: 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, इसलिए मुझे लगता है कि करने के लिए, स्थगित जब तक आप मुझे चाहते हैं कुछ विशिष्ट व्याख्या करने के लिए होगा।

संबंधित मुद्दे