如何使用生命周期来嵌套可变访问?

时间:2016-05-06 15:03:19

标签: iterator streaming rust lifetime borrow-checker

我在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 个答案:

答案 0 :(得分: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);
}