2017-11-09 23 views
1

다음 녹 코드는 컴파일에 실패String :: chars의 소유 버전이 있습니까?</p>이 <pre><code>use std::str::Chars; struct Chunks { remaining: Chars, } impl Chunks { fn new(s: String) -> Self { Chunks { remaining: s.chars(), } } } </code></pre> <p>컴파일러는 불평 :

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

Chars 문자가 반복 처리하고,이 &str 또는 String이 생성 된 오래 살 수를 보유하고 있지 않습니다 에서.

평생 매개 변수가 필요하지 않은 소유 버전 Chars이 있습니까? 아니면 Vec<char>과 색인을 직접 보관해야합니까?

답변

2

std::vec::IntoIter은 모든 이터레이터의 소유 버전입니다.

Playground link

단점

use std::vec::IntoIter; 

struct Chunks { 
    remaining: IntoIter<char>, 
} 

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

추가 할당 및 공간 오버 헤드,하지만 난 당신의 특정 경우에 대한 반복자 인식하지입니다.

1

당신은 당신의 자신의 반복자를 구현하거나, (하나 개의 작은 unsafe 블록)이 같은 Chars을 포장 수 :

// 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://stackoverflow.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

+2

을 [ 같은 것] (https://play.rust-lang.org/?gist=8a5cc326c0fa08cafe7733251ac53546&version=stable), [대여 상자] (https : // 상자 .io/상자/대여). 불행히도 놀이터에서는 작동하지 않습니다. – red75prime

+0

왜 여분 상자가 필요한가요? 'S'는 오직'String','Box '또는 다른 종류의'str' 참조 만 가질 수 있습니다, 맞습니까? 따라서 저장소는 할당 된 힙이어야하며 ('정적'이 아닌 경우) 'S'가 삭제 될 때까지 이동하지 않습니다. (OwnedChars가 물건을 '밀어 넣거나'움직이지 않는 한) – trentcl

+0

작은 문자열 최적화로 문자열 저장 유형을 만들 수 있습니다 (['smallvec'] (https://crates.io 참조)./crates/smallvec) 만들기). – Stefan

0

를 참조 How can I store a Chars iterator in the same struct as the String it is iterating on?에서 복사로 :

use std::str::Chars; 
use std::mem; 

/// I believe this struct to be safe because the String is 
/// heap-allocated (stable address) and will never be modified 
/// (stable address). `chars` will not outlive the struct, so 
/// lying about the lifetime should be fine. 
/// 
/// TODO: What about during destruction? 
///  `Chars` shouldn't have a destructor... 
struct OwningChars { 
    s: String, 
    chars: Chars<'static>, 
} 

impl OwningChars { 
    fn new(s: String) -> Self { 
     let chars = unsafe { mem::transmute(s.chars()) }; 
     OwningChars { s, chars } 
    }  
} 

impl Iterator for OwningChars { 
    type Item = char; 
    fn next(&mut self) -> Option<Self::Item> { 
     self.chars.next() 
    } 
}