string - स्ट्रिंग का कोई स्वामित्व संस्करण है:: वर्ण?




iterator rust (4)

निम्नलिखित कोड संकलित नहीं करता है:

use std::str::Chars;

struct Chunks {
    remaining: Chars,
}

impl Chunks {
    fn new(s: String) -> Self {
        Chunks {
            remaining: s.chars(),
        }
    }
}

त्रुटि है:

error[E0106]: missing lifetime specifier
 --> src/main.rs:4:16
  |
4 |     remaining: Chars,
  |                ^^^^^ expected lifetime parameter

Chars उन पात्रों के स्वामी नहीं हैं, जो इससे अधिक पुनरावृत्त होते हैं और यह &str या String आउटलाइव नहीं कर सकता है, जिससे इसे बनाया गया था।

क्या Chars का कोई स्वामित्व संस्करण है जिसे जीवन भर पैरामीटर की आवश्यकता नहीं है या क्या मुझे एक Vec<char> और खुद को एक इंडेक्स रखना है?


आप किराए के टोकरे का उपयोग String और एक Chars पुनरावृत्ति वाले एक आत्म-संदर्भात्मक संरचना बनाने के लिए कर सकते हैं:

#[macro_use]
extern crate rental;

rental! {
    mod into_chars {
        pub use std::str::Chars;

        #[rental]
        pub struct IntoChars {
            string: String,
            chars: Chars<'string>,
        }
    }
}

use into_chars::IntoChars;

// All these implementations are based on what `Chars` implements itself

impl Iterator for IntoChars {
    type Item = char;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.rent_mut(|chars| chars.next())
    }

    #[inline]
    fn count(mut self) -> usize {
        self.rent_mut(|chars| chars.count())
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.rent(|chars| chars.size_hint())
    }

    #[inline]
    fn last(mut self) -> Option<Self::Item> {
        self.rent_mut(|chars| chars.last())
    }
}

impl DoubleEndedIterator for IntoChars {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.rent_mut(|chars| chars.next_back())
    }
}

impl std::iter::FusedIterator for IntoChars {}

// And an extension trait for convenience 

trait IntoCharsExt {
    fn into_chars(self) -> IntoChars;
}

impl IntoCharsExt for String {
    fn into_chars(self) -> IntoChars {
        IntoChars::new(self, |s| s.chars())
    }
}

आप अपने स्वयं के पुनरावृत्ति को लागू कर सकते हैं, या इस तरह से Chars लपेट सकते हैं (सिर्फ एक छोटे unsafe ब्लॉक के साथ):

// deriving Clone would be buggy. With Rc<>/Arc<> instead of Box<> it would work though.
struct OwnedChars {
    // struct fields are dropped in order they are declared,
    // see https://.com/a/41056727/1478356
    // with `Chars` it probably doesn't matter, but for good style `inner`
    // should be dropped before `storage`.

    // 'static lifetime must not "escape" lifetime of the struct
    inner: ::std::str::Chars<'static>,
    // we need to box anyway to be sure the inner reference doesn't move when
    // moving the storage, so we can erase the type as well.
    // struct OwnedChar<S: AsRef<str>> { ..., storage: Box<S> } should work too
    storage: Box<AsRef<str>>,
}

impl OwnedChars {
    pub fn new<S: AsRef<str>+'static>(s: S) -> Self {
        let storage = Box::new(s) as Box<AsRef<str>>;
        let raw_ptr : *const str = storage.as_ref().as_ref();
        let ptr : &'static str = unsafe { &*raw_ptr };
        OwnedChars{
            storage: storage,
            inner: ptr.chars(),
        }
    }

    pub fn as_str(&self) -> &str {
        self.inner.as_str()
    }
}

impl Iterator for OwnedChars {
    // just `char` of course
    type Item = <::std::str::Chars<'static> as Iterator>::Item;

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

impl DoubleEndedIterator for OwnedChars {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.inner.next_back()
    }
}

impl Clone for OwnedChars {
    fn clone(&self) -> Self {
        // need a new allocation anyway, so simply go for String, and just
        // clone the remaining string
        OwnedChars::new(String::from(self.inner.as_str()))
    }
}

impl ::std::fmt::Debug for OwnedChars {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let storage : &str = self.storage.as_ref().as_ref();
        f.debug_struct("OwnedChars")
            .field("storage", &storage)
            .field("inner", &self.inner)
            .finish()
    }
}

// easy access
trait StringExt {
    fn owned_chars(self) -> OwnedChars;
}
impl<S: AsRef<str>+'static> StringExt for S {
    fn owned_chars(self) -> OwnedChars {
        OwnedChars::new(self)
    }
}

playground देखें


वहाँ भी स्वामित्व-चार टोकरा है , जो

स्ट्रिंग के लिए एक एक्सटेंशन विशेषता प्रदान करता है, दो तरीकों के साथ, in_chars और _char_indices। ये तरीके समानांतर स्ट्रिंग :: चार्ट और स्ट्रिंग :: char_indices, लेकिन वे इसे बनाने वाले इसे उधार लेने के बजाय स्ट्रिंग का उपभोग करते हैं।


std::vec::IntoIter एक अर्थ में, हर std::vec::IntoIter का एक स्वामित्व संस्करण है।

use std::vec::IntoIter;

struct Chunks {
    remaining: IntoIter<char>,
}

impl Chunks {
    fn new(s: String) -> Self {
        Chunks {
            remaining: s.chars().collect::<Vec<_>>().into_iter(),
        }
    }
}

खेल का मैदान लिंक

डाउनसाइड अतिरिक्त आवंटन और एक स्पेस ओवरहेड है, लेकिन मुझे आपके विशिष्ट मामले के लिए पुनरावृति के बारे में पता नहीं है।






ownership