2016-05-06 3 views
1

Я пишу код в Rust для разбора потоков, trait Stream. Потоки могут состоять из других потоков. Черта StreamIterator дает доступ к подпотокам. Это происходит при анализе tar-файлов, zip-файлов и других файлов, содержащих файлы.Как использовать время жизни для вставки изменяемого доступа?

При написании этого кода я безуспешно сражался с механизмом заимствования.

Приведенный ниже код является упрощенным примером. В main файл открывается как поток. Этот поток передается функции analyze, которая пытается открыть поток как TarStreamIterator для повторения потоков в tar. Каждый встроенный поток также анализируется.

Я думаю, что я мог бы ввести второе время жизни в черту StreamIterator.

use std::io; 
trait Stream<T> { 
    fn read(&mut self) -> io::Result<&[T]>; 
} 
trait StreamIterator<'a,T,S: Stream<T>> { 
    fn next(&'a mut self) -> Option<io::Result<S>>; 
} 
struct FileStream { 
} 
impl<T> Stream<T> for FileStream { 
    fn read(&mut self) -> io::Result<&[T]> { 
     Err(io::Error::new(io::ErrorKind::UnexpectedEof, "")) 
    } 
} 
struct TarStream<'a> { 
    stream: &'a mut Stream<u8> 
} 
impl<'a> Stream<u8> for TarStream<'a> { 
    fn read(&mut self) -> io::Result<&[u8]> { 
     self.stream.read() 
    } 
} 
struct TarStreamIterator<'a> { 
    stream: &'a mut Stream<u8> 
} 
impl<'a> StreamIterator<'a,u8,TarStream<'a>> for TarStreamIterator<'a> { 
    fn next(&'a mut self) -> Option<io::Result<TarStream>> { 
     // todo: read tar header 
     Some(Ok(TarStream{stream: self.stream})) 
    } 
} 
fn analyzeAsTar(s: &mut Stream<u8>) -> bool { 
    let mut tar = TarStreamIterator{stream: s}; 
    while let Some(Ok(mut substream)) = tar.next() { 
     analyze(&mut substream); 
    } 
    true 
} 
fn analyze(s: &mut Stream<u8>) -> bool { 
    analyzeAsTar(s) 
} 
fn main() { 
    let mut fs = FileStream{}; 
    analyze(&mut fs); 
} 

Это дает эту ошибку:

<anon>:38:41: 38:44 error: cannot borrow `tar` as mutable more than once at a time [E0499] 
<anon>:38  while let Some(Ok(mut substream)) = tar.next() { 
                ^~~ 
<anon>:38:41: 38:44 help: see the detailed explanation for E0499 
<anon>:38:41: 38:44 note: previous borrow of `tar` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `tar` until the borrow ends 
<anon>:38  while let Some(Ok(mut substream)) = tar.next() { 
                ^~~ 
<anon>:42:2: 42:2 note: previous borrow ends here 
<anon>:36 fn analyzeAsTar(s: &mut Stream<u8>) -> bool { 
      ... 
<anon>:42 } 
+1

Сложно, вы пытаетесь создать то, что называется потоковым итератором *, который возвращает ссылки на ** сам ** как часть контракта. Есть проекты [1] (https://github.com/emk/rust -streaming) [2] (http://burntsushi.net/rustdoc/fst/trait.Streamer.html), Reddit threads [1] (https://www.reddit.com/r/rust/comments/303a09/looking_for_more_information_on_streaming/), [2] (https://www.reddit.com/r/rust/comments/2t1rxx), [сообщения на форуме] (https://users.rust-lang.org/t/x/1096) и даже [SO questions] (http://stackoverflow.com/q/31969710/155423) о теме. – Shepmaster

ответ

1

Существует обходной путь. Вместо того, чтобы иметь свойство с функцией next(), можно использовать признак с функцией iterate. В приведенном ниже примере TarStreamIterator имеет функцию iterate может принимать замыкание. (В качестве альтернативы, iterator можно было бы назвать for_each.)

Реализация все еще имеет функцию next, но контролер заимствования принимает эту форму.

Этот короткий пример фактически ничего не делает с потоками.

use std::io; 
// generic version of std::io::Read 
trait Stream<T> { 
    fn read(&mut self) -> io::Result<&[T]>; 
} 
trait StreamIterator<T> { 
    // call `f` on each of the streams in the iterator 
    fn iterate<F>(&mut self, mut f: F) where F: FnMut(&mut Stream<T>); 
} 
struct FileStream { 
} 
impl<T> Stream<T> for FileStream { 
    fn read(&mut self) -> io::Result<&[T]> { 
     Err(io::Error::new(io::ErrorKind::UnexpectedEof, "")) 
    } 
} 
struct TarStream<'a> { 
    stream: &'a mut Stream<u8> 
} 
impl<'a> Stream<u8> for TarStream<'a> { 
    fn read(&mut self) -> io::Result<&[u8]> { 
     self.stream.read() 
    } 
} 
struct TarStreamIterator<'a> { 
    stream: &'a mut Stream<u8> 
} 
impl<'a> TarStreamIterator<'a> { 
    // pass the next embedded stream or None if there are no more 
    fn next(&mut self) -> Option<TarStream> { 
     Some(TarStream{stream: self.stream}) 
    } 
} 
impl<'a> StreamIterator<u8> for TarStreamIterator<'a> { 
    fn iterate<F>(&mut self, mut f: F) where F: FnMut(&mut Stream<u8>) { 
     while let Some(mut substream) = self.next() { 
      f(&mut substream); 
     } 
    } 
} 
fn analyze_as_tar(stream: &mut Stream<u8>) { 
    TarStreamIterator{stream: stream}.iterate(|substream| { 
     analyze(substream); 
    }); 
} 
fn analyze(s: &mut Stream<u8>) { 
    analyze_as_tar(s) 
} 
fn main() { 
    let mut fs = FileStream{}; 
    analyze(&mut fs); 
}